
com.github.javaclub.cdl.client.group.SGroupConnection Maven / Gradle / Ivy
The newest version!
package com.github.javaclub.cdl.client.group;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.ResultSet;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Executor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.javaclub.cdl.client.common.DataSourceWrapper;
import com.github.javaclub.cdl.client.common.ExceptionSorter;
import com.github.javaclub.cdl.client.common.ThreadLocalDataSourceIndex;
import com.github.javaclub.cdl.client.group.DBSelector.DataSourceTryer;
import com.github.javaclub.cdl.client.util.ExceptionUtils;
import com.github.javaclub.cdl.client.util.GroupHintParser;
public class SGroupConnection implements Connection {
private static final Logger logger = LoggerFactory.getLogger(SGroupConnection.class);
private boolean closed;
private SGroupDataSource sGroupDataSource;
private String username;
private String password;
private boolean isAutoCommit = true;
private Connection rBaseConnection;
private Connection wBaseConnection;
private DataSourceWrapper rBaseDsWrapper;
private DataSourceWrapper wBaseDsWrapper;
private Set openedStatements = new HashSet(2);
private int transactionIsolation = -1;
public SGroupConnection(SGroupDataSource sGroupDataSource) {
this.sGroupDataSource = sGroupDataSource;
}
public SGroupConnection(SGroupDataSource sGroupDataSource, String username, String password) {
this(sGroupDataSource);
this.username = username;
this.password = password;
}
/*-------------------------- jdbc 规范----------------------------*/
@SuppressWarnings("unchecked")
@Override
public T unwrap(Class iface) throws SQLException {
try {
return (T) this;
} catch (Exception e) {
throw new SQLException(e);
}
}
@Override
public boolean isWrapperFor(Class> iface) throws SQLException {
return this.getClass().isAssignableFrom(iface);
}
@Override
public SGroupStatement createStatement() throws SQLException {
checkClosed();
SGroupStatement stmt = new SGroupStatement(sGroupDataSource, this);
openedStatements.add(stmt);
return stmt;
}
@Override
public SGroupStatement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
SGroupStatement stmt = createStatement();
stmt.setResultSetType(resultSetType);
stmt.setResultSetConcurrency(resultSetConcurrency);
return stmt;
}
@Override
public SGroupStatement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
SGroupStatement stmt = createStatement(resultSetType, resultSetConcurrency);
stmt.setResultSetHoldability(resultSetHoldability);
return stmt;
}
@Override
public SGroupPreparedStatement prepareStatement(String sql) throws SQLException {
checkClosed();
SGroupPreparedStatement stmt = new SGroupPreparedStatement(sGroupDataSource, this, sql);
openedStatements.add(stmt);
return stmt;
}
@Override
public SGroupPreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
SGroupPreparedStatement stmt = prepareStatement(sql);
stmt.setAutoGeneratedKeys(autoGeneratedKeys);
return stmt;
}
@Override
public SGroupPreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
SGroupPreparedStatement stmt = prepareStatement(sql);
stmt.setColumnIndexes(columnIndexes);
return stmt;
}
@Override
public SGroupPreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
SGroupPreparedStatement stmt = prepareStatement(sql);
stmt.setColumnNames(columnNames);
return stmt;
}
@Override
public SGroupPreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
SGroupPreparedStatement stmt = prepareStatement(sql);
stmt.setResultSetType(resultSetType);
stmt.setResultSetConcurrency(resultSetConcurrency);
return stmt;
}
@Override
public SGroupPreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
SGroupPreparedStatement stmt = prepareStatement(sql, resultSetType, resultSetConcurrency);
stmt.setResultSetHoldability(resultSetHoldability);
return stmt;
}
@Override
public SGroupCallableStatement prepareCall(String sql) throws SQLException {
return prepareCall(sql, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
}
@Override
public SGroupCallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return prepareCall(sql, resultSetType, resultSetConcurrency, Integer.MIN_VALUE);
}
@Override
public SGroupCallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
checkClosed();
CallableStatement target;
Connection conn = this.getBaseConnection(sql, false);
if (conn != null) {
sql = GroupHintParser.removeCdlGroupHint(sql);
target = getCallableStatement(conn, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
} else {
Integer dataSourceIndex = GroupHintParser.convertHint2Index(sql);
sql = GroupHintParser.removeCdlGroupHint(sql);
if (dataSourceIndex < 0) {
dataSourceIndex = ThreadLocalDataSourceIndex.getIndex();
}
target = sGroupDataSource.getDBSelector(false).tryExecute(null, getCallableStatementTryer,
this.sGroupDataSource.getRetryingTimes(), sql, resultSetType, resultSetConcurrency, resultSetHoldability,
dataSourceIndex);
}
SGroupCallableStatement stmt = new SGroupCallableStatement(sGroupDataSource, this, target, sql);
if (resultSetType != Integer.MIN_VALUE) {
stmt.setResultSetType(resultSetType);
stmt.setResultSetConcurrency(resultSetConcurrency);
}
if (resultSetHoldability != Integer.MIN_VALUE) {
stmt.setResultSetHoldability(resultSetHoldability);
}
openedStatements.add(stmt);
return stmt;
}
@Override
public String nativeSQL(String sql) throws SQLException {
throw new UnsupportedOperationException("nativeSQL");
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
checkClosed();
if (this.isAutoCommit == autoCommit) {
return;
}
this.isAutoCommit = autoCommit;
if (this.wBaseConnection != null) {
this.wBaseConnection.setAutoCommit(autoCommit);
}
}
@Override
public boolean getAutoCommit() throws SQLException {
checkClosed();
return isAutoCommit;
}
@Override
public void commit() throws SQLException {
checkClosed();
if (isAutoCommit) {
return;
}
if (wBaseConnection != null) {
try {
wBaseConnection.commit();
} catch (SQLException e) {
logger.error("Commit failed on {}:{}", this.wBaseDsWrapper.getDataSourceKey(), e.getMessage());
throw e;
}
}
}
@Override
public void rollback() throws SQLException {
checkClosed();
if (isAutoCommit) {
return;
}
if (wBaseConnection != null) {
try {
wBaseConnection.rollback();
} catch (SQLException e) {
logger.error("Rollback failed on {}:{}",this.wBaseDsWrapper.getDataSourceKey() , e.getMessage());
throw e;
}
}
}
@SuppressWarnings("unchecked")
@Override
public void close() throws SQLException {
if (closed) {
return;
}
closed = true;
List exceptions = new LinkedList();
try {
for (SGroupStatement stmt : openedStatements) {
try {
stmt.close(false);
} catch (SQLException e) {
exceptions.add(e);
}
}
try {
if (rBaseConnection != null && !rBaseConnection.isClosed()) {
rBaseConnection.close();
}
} catch (SQLException e) {
exceptions.add(e);
}
try {
if (wBaseConnection != null && !wBaseConnection.isClosed()) {
wBaseConnection.close();
}
} catch (SQLException e) {
exceptions.add(e);
}
} finally {
openedStatements.clear();
rBaseConnection = null;
wBaseConnection = null;
ThreadLocalDataSourceIndex.clearIndex();
}
ExceptionUtils.throwSQLException(exceptions, "close connection", Collections.EMPTY_LIST);
}
@Override
public boolean isClosed() throws SQLException {
return closed;
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
checkClosed();
if (wBaseConnection != null)
return wBaseConnection.getMetaData();
else if (rBaseConnection != null)
return rBaseConnection.getMetaData();
else {
DBSelector dBSelector = null;
try{
dBSelector = sGroupDataSource.getDBSelector(false); // 优先主库获取meta
}catch(Exception e){
}
if(dBSelector != null && dBSelector.getDataSourceWrapperForMeta() != null){
createNewConnection(dBSelector.getDataSourceWrapperForMeta(),false);
if (wBaseConnection != null){
return wBaseConnection.getMetaData();
}
}else { // 从库获取meta
dBSelector = sGroupDataSource.getDBSelector(true);
if(dBSelector != null && dBSelector.getDataSourceWrapperForMeta() != null){
createNewConnection(dBSelector.getDataSourceWrapperForMeta(),true);
if (rBaseConnection != null){
return rBaseConnection.getMetaData();
}
}
}
}
throw new RuntimeException("not found datasource for metaData");
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public boolean isReadOnly() throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public void setCatalog(String catalog) throws SQLException {
throw new UnsupportedOperationException("setCatalog");
}
@Override
public String getCatalog() throws SQLException {
throw new UnsupportedOperationException("getCatalog");
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
checkClosed();
this.transactionIsolation = level;
}
@Override
public int getTransactionIsolation() throws SQLException {
checkClosed();
return transactionIsolation;
}
@Override
public SQLWarning getWarnings() throws SQLException {
checkClosed();
if (rBaseConnection != null)
return rBaseConnection.getWarnings();
else if (wBaseConnection != null)
return wBaseConnection.getWarnings();
else
return null;
}
@Override
public void clearWarnings() throws SQLException {
checkClosed();
if (rBaseConnection != null)
rBaseConnection.clearWarnings();
if (wBaseConnection != null)
wBaseConnection.clearWarnings();
}
@Override
public Map> getTypeMap() throws SQLException {
throw new UnsupportedOperationException("getTypeMap");
}
@Override
public void setTypeMap(Map> map) throws SQLException {
throw new UnsupportedOperationException("setTypeMap");
}
@Override
public void setHoldability(int holdability) throws SQLException {
throw new UnsupportedOperationException("setHoldability");
}
@Override
public int getHoldability() throws SQLException {
return ResultSet.CLOSE_CURSORS_AT_COMMIT;
}
@Override
public Savepoint setSavepoint() throws SQLException {
throw new UnsupportedOperationException("setSavepoint");
}
@Override
public Savepoint setSavepoint(String name) throws SQLException {
throw new UnsupportedOperationException("setSavepoint");
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
throw new UnsupportedOperationException("rollback");
}
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
throw new UnsupportedOperationException("releaseSavepoint");
}
@Override
public Clob createClob() throws SQLException {
throw new SQLException("not support exception");
}
@Override
public Blob createBlob() throws SQLException {
throw new SQLException("not support exception");
}
@Override
public NClob createNClob() throws SQLException {
throw new SQLException("not support exception");
}
@Override
public SQLXML createSQLXML() throws SQLException {
throw new SQLException("not support exception");
}
@Override
public boolean isValid(int timeout) throws SQLException {
throw new SQLException("not support exception");
}
@Override
public void setClientInfo(String name, String value) throws SQLClientInfoException {
throw new RuntimeException("not support exception");
}
@Override
public void setClientInfo(Properties properties) throws SQLClientInfoException {
throw new RuntimeException("not support exception");
}
@Override
public String getClientInfo(String name) throws SQLException {
throw new SQLException("not support exception");
}
@Override
public Properties getClientInfo() throws SQLException {
throw new SQLException("not support exception");
}
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
throw new SQLException("not support exception");
}
@Override
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
throw new SQLException("not support exception");
}
@Override
public void setSchema(String schema) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public String getSchema() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void abort(Executor executor) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getNetworkTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
/*-------------------------- jdbc ----------------------------*/
Connection getBaseConnection(String sql, boolean isRead) throws SQLException {
int dataSourceIndex = DBSelector.NOT_EXIST_USER_SPECIFIED_INDEX;
if (sql == null) {
dataSourceIndex = ThreadLocalDataSourceIndex.getIndex();
} else {
dataSourceIndex = GroupHintParser.convertHint2Index(sql);
if (dataSourceIndex < 0) {
dataSourceIndex = ThreadLocalDataSourceIndex.getIndex();
}
}
if (dataSourceIndex != DBSelector.NOT_EXIST_USER_SPECIFIED_INDEX) {
if (!isAutoCommit) {
if (wBaseDsWrapper != null && !wBaseDsWrapper.isMatchDataSourceIndex(dataSourceIndex))
throw new SQLException("Transaction in another dataSourceIndex: " + dataSourceIndex);
}
if (isRead) {
if (rBaseDsWrapper != null && !rBaseDsWrapper.isMatchDataSourceIndex(dataSourceIndex))
closeReadConnection();
} else {
if (wBaseDsWrapper != null && !wBaseDsWrapper.isMatchDataSourceIndex(dataSourceIndex))
closeWriteConnection();
}
}
if (isRead && isAutoCommit) {
return wBaseConnection != null && wBaseDsWrapper.hasReadWeight() ? wBaseConnection : rBaseConnection;
} else {
if (wBaseConnection != null) {
this.sGroupDataSource.setWriteTarget(wBaseDsWrapper);
return wBaseConnection;
} else if (rBaseConnection != null && rBaseDsWrapper.hasWriteWeight()) {
wBaseConnection = rBaseConnection;
if (wBaseConnection.getAutoCommit() != isAutoCommit)
wBaseConnection.setAutoCommit(isAutoCommit);
wBaseDsWrapper = rBaseDsWrapper;
this.sGroupDataSource.setWriteTarget(wBaseDsWrapper);
return wBaseConnection;
} else {
return null;
}
}
}
Connection createNewConnection(DataSourceWrapper dsw, boolean isRead) throws SQLException {
Connection conn;
if (username != null)
conn = dsw.getConnection(username, password);
else
conn = dsw.getConnection();
setBaseConnection(conn, dsw, isRead && isAutoCommit);
if (!isRead || !isAutoCommit)
conn.setAutoCommit(isAutoCommit);
return conn;
}
void removeOpenedStatements(Statement statement) {
if (!openedStatements.remove(statement)) {
logger.warn("current statmenet " + statement + " doesn't exist!");
}
}
private void setBaseConnection(Connection baseConnection, DataSourceWrapper dsw, boolean isRead) {
if (baseConnection == null) {
logger.warn("setBaseConnection to null !!");
}
if (isRead)
closeReadConnection();
else
closeWriteConnection();
if (isRead) {
rBaseConnection = baseConnection;
this.rBaseDsWrapper = dsw;
} else {
wBaseConnection = baseConnection;
this.wBaseDsWrapper = dsw;
this.sGroupDataSource.setWriteTarget(dsw);
}
}
private void closeReadConnection() {
if (rBaseConnection != null && rBaseConnection != wBaseConnection) {
try {
rBaseConnection.close();
} catch (SQLException e) {
logger.error("close rBaseConnection failed.", e);
}
rBaseDsWrapper = null;
rBaseConnection = null;
}
}
private void closeWriteConnection() {
if (wBaseConnection != null && wBaseConnection != rBaseConnection ) {
try {
wBaseConnection.close();
} catch (SQLException e) {
logger.error("close wBaseConnection failed.", e);
}
wBaseDsWrapper = null;
wBaseConnection = null;
}
}
private void checkClosed() throws SQLException {
if (closed) {
throw new SQLException("No operations allowed after connection closed.");
}
}
private DataSourceTryer getCallableStatementTryer = new DataSourceTryer() {
@SuppressWarnings("unchecked")
@Override
public CallableStatement onSQLException(List exceptions, ExceptionSorter exceptionSorter, Object... args)
throws SQLException {
ExceptionUtils.throwSQLException(exceptions, null, Collections.EMPTY_LIST);
return null;
}
@Override
public CallableStatement tryOnDataSource(DataSourceWrapper dsw, Object... args) throws SQLException {
String sql = (String) args[0];
int resultSetType = (Integer) args[1];
int resultSetConcurrency = (Integer) args[2];
int resultSetHoldability = (Integer) args[3];
Connection conn = SGroupConnection.this.createNewConnection(dsw, false);
return getCallableStatement(conn, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
};
private CallableStatement getCallableStatement(Connection conn, String sql, int resultSetType, int resultSetConcurrency,
int resultSetHoldability) throws SQLException {
if (resultSetType == Integer.MIN_VALUE) {
return conn.prepareCall(sql);
} else if (resultSetHoldability == Integer.MIN_VALUE) {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
} else {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
}
public Connection getrBaseConnection() {
return rBaseConnection;
}
public void setrBaseConnection(Connection rBaseConnection) {
this.rBaseConnection = rBaseConnection;
}
public Connection getwBaseConnection() {
return wBaseConnection;
}
public void setwBaseConnection(Connection wBaseConnection) {
this.wBaseConnection = wBaseConnection;
}
public DataSourceWrapper getrBaseDsWrapper() {
return rBaseDsWrapper;
}
public void setrBaseDsWrapper(DataSourceWrapper rBaseDsWrapper) {
this.rBaseDsWrapper = rBaseDsWrapper;
}
public DataSourceWrapper getwBaseDsWrapper() {
return wBaseDsWrapper;
}
public void setwBaseDsWrapper(DataSourceWrapper wBaseDsWrapper) {
this.wBaseDsWrapper = wBaseDsWrapper;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy