io.github.bucket4j.oracle.OracleSelectForUpdateBasedProxyManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bucket4j_jdk8-oracle Show documentation
Show all versions of bucket4j_jdk8-oracle Show documentation
bucket4j - is a java implementation of token bucket algorithm for rate limiting
The newest version!
/*-
* ========================LICENSE_START=================================
* Bucket4j
* %%
* Copyright (C) 2015 - 2022 Vladimir Bukhtoyarov
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =========================LICENSE_END==================================
*/
package io.github.bucket4j.oracle;
import io.github.bucket4j.BucketExceptions;
import io.github.bucket4j.distributed.jdbc.BucketTableSettings;
import io.github.bucket4j.distributed.jdbc.SQLProxyConfiguration;
import io.github.bucket4j.distributed.jdbc.SQLProxyConfigurationBuilder;
import io.github.bucket4j.distributed.proxy.ClientSideConfig;
import io.github.bucket4j.distributed.proxy.generic.select_for_update.AbstractSelectForUpdateBasedProxyManager;
import io.github.bucket4j.distributed.proxy.generic.select_for_update.LockAndGetResult;
import io.github.bucket4j.distributed.proxy.generic.select_for_update.SelectForUpdateBasedTransaction;
import io.github.bucket4j.distributed.remote.RemoteBucketState;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.text.MessageFormat;
import java.util.Objects;
import java.util.Optional;
/**
* @author Vladimir Bukhtoyarov
*
* @param type of primary key
*/
public class OracleSelectForUpdateBasedProxyManager extends AbstractSelectForUpdateBasedProxyManager {
private final DataSource dataSource;
private final SQLProxyConfiguration configuration;
private final String removeSqlQuery;
private final String updateSqlQuery;
private final String insertSqlQuery;
private final String selectSqlQuery;
/**
*
* @param configuration {@link SQLProxyConfiguration} configuration.
*/
public OracleSelectForUpdateBasedProxyManager(SQLProxyConfiguration configuration) {
super(configuration.getClientSideConfig());
this.dataSource = Objects.requireNonNull(configuration.getDataSource());
this.configuration = configuration;
this.removeSqlQuery = MessageFormat.format("DELETE FROM {0} WHERE {1} = ?", configuration.getTableName(), configuration.getIdName());
this.updateSqlQuery = MessageFormat.format("UPDATE {0} SET {1}=? WHERE {2}=?", configuration.getTableName(), configuration.getStateName(), configuration.getIdName());
//this.insertSqlQuery = MessageFormat.format("INSERT INTO {0}({1}, {2}) VALUES(?, null) ON CONFLICT({3}) DO NOTHING",
this.insertSqlQuery = MessageFormat.format(
"MERGE INTO {0} b1\n" +
"USING (SELECT ? {1} FROM dual) b2\n" +
"ON (b1.{1} = b2.{1})\n" +
"WHEN NOT matched THEN\n" +
"INSERT ({1}, {2}) VALUES (?, null)",
configuration.getTableName(), configuration.getIdName(), configuration.getStateName(), configuration.getIdName());
this.selectSqlQuery = MessageFormat.format("SELECT {0} FROM {1} WHERE {2} = ? FOR UPDATE", configuration.getStateName(), configuration.getTableName(), configuration.getIdName());
}
@Override
protected SelectForUpdateBasedTransaction allocateTransaction(K key, Optional requestTimeoutNanos) {
Connection connection;
try {
connection = dataSource.getConnection();
} catch (SQLException e) {
throw new BucketExceptions.BucketExecutionException(e);
}
return new SelectForUpdateBasedTransaction() {
@Override
public void begin(Optional requestTimeoutNanos) {
try {
connection.setAutoCommit(false);
} catch (SQLException e) {
throw new BucketExceptions.BucketExecutionException(e);
}
}
@Override
public void rollback() {
try {
connection.rollback();
} catch (SQLException e) {
throw new BucketExceptions.BucketExecutionException(e);
}
}
@Override
public void commit(Optional requestTimeoutNanos) {
try {
connection.commit();
} catch (SQLException e) {
throw new BucketExceptions.BucketExecutionException(e);
}
}
@Override
public LockAndGetResult tryLockAndGet(Optional requestTimeoutNanos) {
try (PreparedStatement selectStatement = connection.prepareStatement(selectSqlQuery)) {
applyTimeout(selectStatement, requestTimeoutNanos);
configuration.getPrimaryKeyMapper().set(selectStatement, 1, key);
try (ResultSet rs = selectStatement.executeQuery()) {
if (rs.next()) {
byte[] data = rs.getBytes(configuration.getStateName());
return LockAndGetResult.locked(data);
} else {
return LockAndGetResult.notLocked();
}
}
} catch (SQLException e) {
throw new BucketExceptions.BucketExecutionException(e);
}
}
@Override
public boolean tryInsertEmptyData(Optional requestTimeoutNanos) {
try (PreparedStatement insertStatement = connection.prepareStatement(insertSqlQuery)) {
applyTimeout(insertStatement, requestTimeoutNanos);
configuration.getPrimaryKeyMapper().set(insertStatement, 1, key);
configuration.getPrimaryKeyMapper().set(insertStatement, 2, key);
return insertStatement.executeUpdate() > 0;
} catch (SQLIntegrityConstraintViolationException integrityException) {
return false;
} catch (SQLException e) {
throw new BucketExceptions.BucketExecutionException(e);
}
}
@Override
public void update(byte[] data, RemoteBucketState newState, Optional requestTimeoutNanos) {
try {
try (PreparedStatement updateStatement = connection.prepareStatement(updateSqlQuery)) {
applyTimeout(updateStatement, requestTimeoutNanos);
updateStatement.setBytes(1, data);
configuration.getPrimaryKeyMapper().set(updateStatement, 2, key);
updateStatement.executeUpdate();
}
} catch (SQLException e) {
throw new BucketExceptions.BucketExecutionException(e);
}
}
@Override
public void release() {
try {
connection.close();
} catch (SQLException e) {
throw new BucketExceptions.BucketExecutionException(e);
}
}
};
}
@Override
public void removeProxy(K key) {
try (Connection connection = dataSource.getConnection()) {
try(PreparedStatement removeStatement = connection.prepareStatement(removeSqlQuery)) {
configuration.getPrimaryKeyMapper().set(removeStatement, 1, key);
removeStatement.executeUpdate();
}
} catch (SQLException e) {
throw new BucketExceptions.BucketExecutionException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy