All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.javaclub.cdl.client.group.SGroupStatement Maven / Gradle / Ivy

There is a newer version: 2.3.9
Show newest version
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