
com.github.javaclub.cdl.client.group.SGroupStatement Maven / Gradle / Ivy
package com.github.javaclub.cdl.client.group;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
//import com.shangou.trace.cdl.CDLBraveTrace;
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.SQLParser;
import com.github.javaclub.cdl.client.common.SqlType;
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;
import com.github.javaclub.cdl.client.util.SQLMonitors;
public class SGroupStatement implements Statement {
private static final Logger logger = LoggerFactory.getLogger(SGroupStatement.class);
protected boolean closed;
protected ResultSet currentResultSet;
protected SGroupDataSource sGroupDataSource;
protected SGroupConnection sGroupConnection;
protected int resultSetHoldability = -1;
protected int resultSetType = ResultSet.TYPE_FORWARD_ONLY;;
protected int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY;
protected int queryTimeout = 0;
protected int fetchSize;
protected int maxRows;
protected int retryingTimes;
private Statement baseStatement;
protected int updateCount;
protected List batchedArgs;
public SGroupStatement(SGroupDataSource sGroupDataSource, SGroupConnection sGroupConnection) {
this.sGroupDataSource = sGroupDataSource;
this.sGroupConnection = sGroupConnection;
}
/*-------------------------- 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 ResultSet executeQuery(String sql) throws SQLException {
boolean result = true;
try{
SQLMonitors.entry(sql);
if(sGroupDataSource.getDbConfigManager().isEnableTrace()){
// CDLBraveTrace.beginTrace(sql,sGroupDataSource.getGroupName());
}
checkClosed();
ensureResultSetIsEmpty();
boolean isSelect = SqlType.SELECT.equals(SQLParser.getSqlType(sql));
boolean gotoRead = isSelect && sGroupConnection.getAutoCommit();
synchronized (sGroupConnection) { // 同一个连接上面执行多次时,要顺序执行,否则有并发问题
Connection conn = sGroupConnection.getBaseConnection(sql, gotoRead);
if (conn != null) {
sql = GroupHintParser.removeCdlGroupHint(sql);
return executeQueryOnConnection(conn, sql);
} else {
Integer dataSourceIndex = GroupHintParser.convertHint2Index(sql);
sql = GroupHintParser.removeCdlGroupHint(sql);
if (dataSourceIndex < 0) {
dataSourceIndex = ThreadLocalDataSourceIndex.getIndex();
}
if(!gotoRead && isSelect){ // 事务里面的查询先强制走主库
try{
return sGroupDataSource.getDBSelector(false).tryExecute(executeQueryTryer, retryingTimes, sql, dataSourceIndex);
}catch(Exception e){
}
// 事务里面的查询前面没有找到主库,重试一次从库
return this.sGroupDataSource.getDBSelector(true).tryExecute(executeQueryTryer, retryingTimes, sql, dataSourceIndex);
}
return this.sGroupDataSource.getDBSelector(gotoRead).tryExecute(executeQueryTryer, retryingTimes, sql, dataSourceIndex);
}
}
} catch(SQLException e){
result = false;
throw e;
} finally{
if(sGroupDataSource.getDbConfigManager().isEnableTrace()){
// CDLBraveTrace.endTrace(null);
}
SQLMonitors.exit(sql, result);
}
}
@Override
public int executeUpdate(String sql) throws SQLException {
boolean result = true;
try{
SQLMonitors.entry(sql);
if(sGroupDataSource.getDbConfigManager().isEnableTrace()){
//CDLBraveTrace.beginTrace(sql,sGroupDataSource.getGroupName());
}
return executeUpdateInternal(sql, -1, null, null);
} catch(SQLException e){
result = false;
throw e;
} finally{
if(sGroupDataSource.getDbConfigManager().isEnableTrace()){
//CDLBraveTrace.endTrace(null);
}
SQLMonitors.exit(sql, result);
}
}
@Override
public void close() throws SQLException {
close(true);
}
@Override
public int getMaxFieldSize() throws SQLException {
throw new UnsupportedOperationException("getMaxFieldSize");
}
@Override
public void setMaxFieldSize(int max) throws SQLException {
throw new UnsupportedOperationException("setMaxFieldSize");
}
@Override
public int getMaxRows() throws SQLException {
return this.maxRows;
}
@Override
public void setMaxRows(int maxRows) throws SQLException {
this.maxRows = maxRows;
}
@Override
public void setEscapeProcessing(boolean enable) throws SQLException {
throw new UnsupportedOperationException("setEscapeProcessing");
}
@Override
public int getQueryTimeout() throws SQLException {
return queryTimeout;
}
@Override
public void setQueryTimeout(int queryTimeout) throws SQLException {
this.queryTimeout = queryTimeout;
}
@Override
public void cancel() throws SQLException {
throw new UnsupportedOperationException("cancel");
}
@Override
public SQLWarning getWarnings() throws SQLException {
checkClosed();
if (baseStatement != null)
return baseStatement.getWarnings();
return null;
}
@Override
public void clearWarnings() throws SQLException {
checkClosed();
if (baseStatement != null)
baseStatement.clearWarnings();
}
@Override
public void setCursorName(String name) throws SQLException {
throw new UnsupportedOperationException("setCursorName");
}
@Override
public boolean execute(String sql) throws SQLException {
return executeInternal(sql, -1, null, null);
}
@Override
public ResultSet getResultSet() throws SQLException {
return currentResultSet;
}
@Override
public int getUpdateCount() throws SQLException {
return updateCount;
}
@Override
public boolean getMoreResults() throws SQLException {
throw new UnsupportedOperationException("getMoreResults");
}
@Override
public void setFetchDirection(int direction) throws SQLException {
throw new UnsupportedOperationException("setFetchDirection");
}
@Override
public int getFetchDirection() throws SQLException {
throw new UnsupportedOperationException("getFetchDirection");
}
@Override
public void setFetchSize(int fetchSize) throws SQLException {
this.fetchSize = fetchSize;
}
@Override
public int getFetchSize() throws SQLException {
return this.fetchSize;
}
@Override
public int getResultSetConcurrency() throws SQLException {
return resultSetConcurrency;
}
@Override
public int getResultSetType() throws SQLException {
return resultSetType;
}
@Override
public void addBatch(String sql) throws SQLException {
checkClosed();
if (batchedArgs == null) {
batchedArgs = new LinkedList();
}
if (sql != null) {
batchedArgs.add(sql);
}
}
@Override
public void clearBatch() throws SQLException {
checkClosed();
if (batchedArgs != null) {
batchedArgs.clear();
}
}
@Override
public int[] executeBatch() throws SQLException {
try {
checkClosed();
ensureResultSetIsEmpty();
if (batchedArgs == null || batchedArgs.isEmpty()) {
return new int[0];
}
synchronized (sGroupConnection) { // 同一个连接上面执行多次时,要顺序执行,否则有并发问题
Connection conn = sGroupConnection.getBaseConnection(null, false);
if (conn != null) {
return executeBatchOnConnection(conn, this.batchedArgs);
} else {
return sGroupDataSource.getDBSelector(false).tryExecute(null, executeBatchTryer, retryingTimes);
}
}
} finally {
if (batchedArgs != null)
batchedArgs.clear();
}
}
@Override
public Connection getConnection() throws SQLException {
return sGroupConnection;
}
@Override
public boolean getMoreResults(int current) throws SQLException {
throw new UnsupportedOperationException("getMoreResults");
}
@Override
public ResultSet getGeneratedKeys() throws SQLException {
if (this.baseStatement != null)
return this.baseStatement.getGeneratedKeys();
else
throw new SQLException("在调用getGeneratedKeys前未执行过任何更新操作");
}
@Override
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
return executeUpdateInternal(sql, autoGeneratedKeys, null, null);
}
@Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
return executeUpdateInternal(sql, -1, columnIndexes, null);
}
@Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException {
return executeUpdateInternal(sql, -1, null, columnNames);
}
@Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
return executeInternal(sql, autoGeneratedKeys, null, null);
}
@Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException {
return executeInternal(sql, -1, columnIndexes, null);
}
@Override
public boolean execute(String sql, String[] columnNames) throws SQLException {
return executeInternal(sql, -1, null, columnNames);
}
@Override
public int getResultSetHoldability() throws SQLException {
return resultSetHoldability;
}
@Override
public boolean isClosed() throws SQLException {
throw new SQLException("not support exception");
}
@Override
public void setPoolable(boolean poolable) throws SQLException {
throw new SQLException("not support exception");
}
@Override
public boolean isPoolable() throws SQLException {
throw new SQLException("not support exception");
}
@Override
public void closeOnCompletion() throws SQLException {
throw new SQLException("not support exception");
}
@Override
public boolean isCloseOnCompletion() throws SQLException {
throw new SQLException("not support exception");
}
/*-------------------------- jdbc 规范 -----------------------------*/
protected DataSourceTryer executeQueryTryer = new DataSourceTryer() {
@SuppressWarnings("unchecked")
@Override
public ResultSet onSQLException(List exceptions, ExceptionSorter exceptionSorter, Object... args) throws SQLException {
ExceptionUtils.throwSQLException(exceptions, null, Collections.EMPTY_LIST);
return null;
}
@Override
public ResultSet tryOnDataSource(DataSourceWrapper dsw, Object... args) throws SQLException {
String sql = (String) args[0];
Connection conn = SGroupStatement.this.sGroupConnection.createNewConnection(dsw, true);
return executeQueryOnConnection(conn, sql);
}
};
private int executeUpdateOnConnection(Connection conn, String sql, int autoGeneratedKeys, int[] columnIndexes, String[] columnNames)
throws SQLException {
Statement stmt = createStatementInternal(conn, false);
if (autoGeneratedKeys == -1 && columnIndexes == null && columnNames == null) {
return stmt.executeUpdate(sql);
} else if (autoGeneratedKeys != -1) {
return stmt.executeUpdate(sql, autoGeneratedKeys);
} else if (columnIndexes != null) {
return stmt.executeUpdate(sql, columnIndexes);
} else if (columnNames != null) {
return stmt.executeUpdate(sql, columnNames);
} else {
return stmt.executeUpdate(sql);
}
}
protected ResultSet executeQueryOnConnection(Connection conn, String sql) throws SQLException {
Statement stmt = createStatementInternal(conn, false);
this.currentResultSet = stmt.executeQuery(sql);
return this.currentResultSet;
}
private Statement createStatementInternal(Connection conn, boolean isBatch) throws SQLException {
Statement stmt;
if (isBatch)
stmt = conn.createStatement();
else {
int resultSetHoldability = this.resultSetHoldability;
if (resultSetHoldability == -1)
resultSetHoldability = conn.getHoldability();
stmt = conn.createStatement(this.resultSetType, this.resultSetConcurrency, resultSetHoldability);
}
setBaseStatement(stmt);
stmt.setQueryTimeout(queryTimeout);
stmt.setFetchSize(fetchSize);
stmt.setMaxRows(maxRows);
return stmt;
}
private int executeUpdateInternal(String sql, int autoGeneratedKeys, int[] columnIndexes, String[] columnNames) throws SQLException {
checkClosed();
ensureResultSetIsEmpty();
synchronized (sGroupConnection) { // 同一个连接上面执行多次时,要顺序执行,否则有并发问题
Connection conn = sGroupConnection.getBaseConnection(sql, false);
if (conn != null) {
sql = GroupHintParser.removeCdlGroupHint(sql);
this.updateCount = executeUpdateOnConnection(conn, sql, autoGeneratedKeys, columnIndexes, columnNames);
return this.updateCount;
} else {
Integer dataSourceIndex = GroupHintParser.convertHint2Index(sql);
sql = GroupHintParser.removeCdlGroupHint(sql);
if (dataSourceIndex < 0) {
dataSourceIndex = ThreadLocalDataSourceIndex.getIndex();
}
this.updateCount = this.sGroupDataSource.getDBSelector(false).tryExecute(executeUpdateTryer, retryingTimes, sql,
autoGeneratedKeys, columnIndexes, columnNames, dataSourceIndex);
return this.updateCount;
}
}
}
private boolean executeInternal(String sql, int autoGeneratedKeys, int[] columnIndexes, String[] columnNames) throws SQLException {
SqlType sqlType = SQLParser.getSqlType(sql);
if (sqlType == SqlType.SELECT || sqlType == SqlType.SELECT_FOR_UPDATE || sqlType == SqlType.SHOW) {
executeQuery(sql);
return true;
} else if (sqlType == SqlType.INSERT || sqlType == SqlType.UPDATE || sqlType == SqlType.DELETE || sqlType == SqlType.REPLACE
|| sqlType == SqlType.TRUNCATE || sqlType == SqlType.CREATE || sqlType == SqlType.DROP || sqlType == SqlType.LOAD
|| sqlType == SqlType.MERGE) {
if (autoGeneratedKeys == -1 && columnIndexes == null && columnNames == null) {
executeUpdate(sql);
} else if (autoGeneratedKeys != -1) {
executeUpdate(sql, autoGeneratedKeys);
} else if (columnIndexes != null) {
executeUpdate(sql, columnIndexes);
} else if (columnNames != null) {
executeUpdate(sql, columnNames);
} else {
executeUpdate(sql);
}
return false;
} else {
throw new SQLException("only select, insert, update, delete,replace,truncate,create,drop,load,merge sql is supported");
}
}
private DataSourceTryer executeUpdateTryer = new DataSourceTryer() {
@SuppressWarnings("unchecked")
@Override
public Integer onSQLException(List exceptions, ExceptionSorter exceptionSorter, Object... args) throws SQLException {
ExceptionUtils.throwSQLException(exceptions, null, Collections.EMPTY_LIST);
return null;
}
@Override
public Integer tryOnDataSource(DataSourceWrapper dsw, Object... args) throws SQLException {
Connection conn = SGroupStatement.this.sGroupConnection.createNewConnection(dsw, false);
return executeUpdateOnConnection(conn, (String) args[0], (Integer) args[1], (int[]) args[2], (String[]) args[3]);
}
};
protected int[] executeBatchOnConnection(Connection conn, List batchedSqls) throws SQLException {
Statement stmt = createStatementInternal(conn, true);
for (String sql : batchedSqls) {
stmt.addBatch(sql);
}
return stmt.executeBatch();
}
private DataSourceTryer executeBatchTryer = new DataSourceTryer() {
@SuppressWarnings("unchecked")
@Override
public int[] onSQLException(List exceptions, ExceptionSorter exceptionSorter, Object... args) throws SQLException {
ExceptionUtils.throwSQLException(exceptions, null, Collections.EMPTY_LIST);
return null;
}
@Override
public int[] tryOnDataSource(DataSourceWrapper dsw, Object... args) throws SQLException {
Connection conn = SGroupStatement.this.sGroupConnection.createNewConnection(dsw, false);
return executeBatchOnConnection(conn, SGroupStatement.this.batchedArgs);
}
};
void setBaseStatement(Statement baseStatement) {
if (this.baseStatement != null) {
try {
this.baseStatement.close();
} catch (SQLException e) {
logger.error("close baseStatement failed.", e);
}
}
this.baseStatement = baseStatement;
}
protected void checkClosed() throws SQLException {
if (closed) {
throw new SQLException("No operations allowed after statement closed.");
}
}
void close(boolean removeThis) throws SQLException {
if (closed) {
return;
}
closed = true;
try {
if (currentResultSet != null)
currentResultSet.close();
} catch (SQLException e) {
logger.warn("Close currentResultSet failed.", e);
} finally {
currentResultSet = null;
}
try {
if (this.baseStatement != null)
this.baseStatement.close();
} finally {
this.baseStatement = null;
if (removeThis)
sGroupConnection.removeOpenedStatements(this);
}
}
protected void ensureResultSetIsEmpty() throws SQLException {
if (currentResultSet != null) {
try {
currentResultSet.close();
} catch (SQLException e) {
logger.error("exception on close last result set . can do nothing..", e);
} finally {
currentResultSet = null;
}
}
}
public ResultSet getCurrentResultSet() {
return currentResultSet;
}
public void setCurrentResultSet(ResultSet currentResultSet) {
this.currentResultSet = currentResultSet;
}
public SGroupDataSource getsGroupDataSource() {
return sGroupDataSource;
}
public void setsGroupDataSource(SGroupDataSource sGroupDataSource) {
this.sGroupDataSource = sGroupDataSource;
}
public SGroupConnection getsGroupConnection() {
return sGroupConnection;
}
public void setsGroupConnection(SGroupConnection sGroupConnection) {
this.sGroupConnection = sGroupConnection;
}
public int getRetryingTimes() {
return retryingTimes;
}
public void setRetryingTimes(int retryingTimes) {
this.retryingTimes = retryingTimes;
}
public List getBatchedArgs() {
return batchedArgs;
}
public void setBatchedArgs(List batchedArgs) {
this.batchedArgs = batchedArgs;
}
public DataSourceTryer getExecuteQueryTryer() {
return executeQueryTryer;
}
public void setExecuteQueryTryer(DataSourceTryer executeQueryTryer) {
this.executeQueryTryer = executeQueryTryer;
}
public DataSourceTryer getExecuteUpdateTryer() {
return executeUpdateTryer;
}
public void setExecuteUpdateTryer(DataSourceTryer executeUpdateTryer) {
this.executeUpdateTryer = executeUpdateTryer;
}
public DataSourceTryer getExecuteBatchTryer() {
return executeBatchTryer;
}
public void setExecuteBatchTryer(DataSourceTryer executeBatchTryer) {
this.executeBatchTryer = executeBatchTryer;
}
public Statement getBaseStatement() {
return baseStatement;
}
public void setClosed(boolean closed) {
this.closed = closed;
}
public void setResultSetHoldability(int resultSetHoldability) {
this.resultSetHoldability = resultSetHoldability;
}
public void setResultSetType(int resultSetType) {
this.resultSetType = resultSetType;
}
public void setResultSetConcurrency(int resultSetConcurrency) {
this.resultSetConcurrency = resultSetConcurrency;
}
public void setUpdateCount(int updateCount) {
this.updateCount = updateCount;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy