package com.taobao.tddl.matrix.jdbc; 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.PreparedStatement; 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.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ExecutorService; import org.apache.commons.lang.StringUtils; import com.taobao.tddl.common.exception.TddlException; import com.taobao.tddl.common.jdbc.ParameterContext; import com.taobao.tddl.common.utils.TStringUtil; import com.taobao.tddl.executor.MatrixExecutor; import com.taobao.tddl.executor.common.ExecutionContext; import com.taobao.tddl.executor.common.ExecutorContext; import com.taobao.tddl.executor.cursor.ResultCursor; import com.taobao.tddl.executor.cursor.impl.ResultSetCursor; import com.taobao.tddl.executor.spi.ITransaction; import com.taobao.tddl.group.utils.GroupHintParser; import com.taobao.tddl.matrix.jdbc.utils.ExceptionUtils; import com.taobao.tddl.optimizer.OptimizerContext; /** * @author mengshi.sunmengshi 2013-11-22 下午3:26:06 * @since 5.0.0 */ public class TConnection implements Connection { private MatrixExecutor executor = null; private final TDataSource ds; private ExecutionContext executionContext = new ExecutionContext(); // 记录上一次的执行上下文 private final List<TStatement> openedStatements = Collections.synchronizedList(new ArrayList<TStatement>(2)); private boolean isAutoCommit = true; // jdbc规范,新连接为true private boolean closed; private int transactionIsolation = -1; private final ExecutorService executorService; public TConnection(TDataSource ds){ this.ds = ds; this.executor = ds.getExecutor(); this.executorService = ds.borrowExecutorService(); } /** * 执行sql语句的逻辑 */ public ResultSet executeSQL(String sql, Map<Integer, ParameterContext> context, TStatement stmt, Map<String, Object> extraCmd, ExecutionContext executionContext) throws SQLException { ExecutorContext.setContext(this.ds.getConfigHolder().getExecutorContext()); OptimizerContext.setContext(this.ds.getConfigHolder().getOptimizerContext()); ResultCursor resultCursor; ResultSet rs = null; extraCmd.putAll(buildExtraCommand(sql)); // 处理下group hint String groupHint = GroupHintParser.extractTDDLGroupHint(sql); if (!StringUtils.isEmpty(groupHint)) { sql = GroupHintParser.removeTddlGroupHint(sql); executionContext.setGroupHint(GroupHintParser.buildTddlGroupHint(groupHint)); } executionContext.setExecutorService(executorService); executionContext.setParams(context); executionContext.setExtraCmds(extraCmd); try { resultCursor = executor.execute(sql, executionContext); } catch (TddlException e) { throw new SQLException(e); } if (resultCursor instanceof ResultSetCursor) { rs = ((ResultSetCursor) resultCursor).getResultSet(); } else { rs = new TResultSet(resultCursor); } return rs; } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { checkClosed(); ExecutionContext context = prepareExecutionContext(); TPreparedStatement stmt = new TPreparedStatement(ds, this, sql, context); openedStatements.add(stmt); return stmt; } @Override public Statement createStatement() throws SQLException { checkClosed(); ExecutionContext context = prepareExecutionContext(); TStatement stmt = new TStatement(ds, this, context); openedStatements.add(stmt); return stmt; } private ExecutionContext prepareExecutionContext() { if (isAutoCommit) { // 即使为autoCommit也需要记录 // 因为在JDBC规范中,只要在statement.execute执行之前,设置autoCommit=false都是有效的 this.executionContext = new ExecutionContext(); } else { if (this.executionContext == null) { this.executionContext = new ExecutionContext(); } if (this.executionContext.isAutoCommit()) { this.executionContext.setAutoCommit(false); } } return this.executionContext; } /* * ======================================================================== * JDBC事务相关的autoCommit设置、commit/rollback、TransactionIsolation等 * ====================================================================== */ @Override public void setAutoCommit(boolean autoCommit) throws SQLException { checkClosed(); if (this.isAutoCommit == autoCommit) { // 先排除两种最常见的状态,true==true 和false == false: 什么也不做 return; } this.isAutoCommit = autoCommit; if (this.executionContext != null) { this.executionContext.setAutoCommit(autoCommit); } } @Override public boolean getAutoCommit() throws SQLException { checkClosed(); return isAutoCommit; } @Override public void commit() throws SQLException { checkClosed(); if (isAutoCommit) { return; } if (this.executionContext != null) { try { // 事务结束,清理事务内容 this.executor.commit(this.executionContext); ITransaction transtion = this.executionContext.getTransaction(); if (transtion != null) { transtion.close(); } this.executionContext = null; } catch (TddlException e) { throw new SQLException(e); } } } @Override public void rollback() throws SQLException { checkClosed(); if (isAutoCommit) { return; } if (this.executionContext != null) { try { this.executor.rollback(executionContext); // 事务结束,清理事务内容 ITransaction transtion = this.executionContext.getTransaction(); if (transtion != null) { transtion.close(); } this.executionContext = null; } catch (TddlException e) { throw new SQLException(e); } } } @Override public DatabaseMetaData getMetaData() throws SQLException { checkClosed(); return new TDatabaseMetaData(); } private void checkClosed() throws SQLException { if (closed) { throw new SQLException("No operations allowed after connection closed."); } } @Override public boolean isClosed() throws SQLException { return closed; } @Override public void close() throws SQLException { if (closed) { return; } List<SQLException> exceptions = new LinkedList<SQLException>(); try { // 关闭statement for (TStatement stmt : openedStatements) { try { stmt.close(false); } catch (SQLException e) { exceptions.add(e); } } } finally { openedStatements.clear(); } if (executorService != null) { this.ds.releaseExecutorService(executorService); } if (this.executionContext != null && this.executionContext.getTransaction() != null) { try { this.executionContext.getTransaction().close(); } catch (TddlException e) { exceptions.add(new SQLException(e)); } } closed = true; ExceptionUtils.throwSQLException(exceptions, "close tconnection", Collections.EMPTY_LIST); } private Map<String, Object> buildExtraCommand(String sql) { Map<String, Object> extraCmd = new HashMap(); String andorExtra = "/* ANDOR "; String tddlExtra = "/* TDDL "; if (sql != null) { String commet = TStringUtil.substringAfter(sql, tddlExtra); // 去掉注释 if (TStringUtil.isNotEmpty(commet)) { commet = TStringUtil.substringBefore(commet, "*/"); } if (TStringUtil.isEmpty(commet) && sql.startsWith(andorExtra)) { commet = TStringUtil.substringAfter(sql, andorExtra); commet = TStringUtil.substringBefore(commet, "*/"); } if (TStringUtil.isNotEmpty(commet)) { String[] params = commet.split(","); for (String param : params) { String[] keyAndVal = param.split("="); if (keyAndVal.length != 2) { throw new IllegalArgumentException(param + " is wrong , only key = val supported"); } String key = keyAndVal[0]; String val = keyAndVal[1]; extraCmd.put(key, val); } } } extraCmd.putAll(this.ds.getConnectionProperties()); return extraCmd; } /** * 未实现方法 */ @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { TStatement stmt = (TStatement) createStatement(); stmt.setResultSetType(resultSetType); stmt.setResultSetConcurrency(resultSetConcurrency); return stmt; } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { throw new UnsupportedOperationException(); } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { throw new UnsupportedOperationException(); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { throw new UnsupportedOperationException(); } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { throw new UnsupportedOperationException(); } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { throw new UnsupportedOperationException(); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { throw new UnsupportedOperationException(); } @Override public CallableStatement prepareCall(String sql) throws SQLException { throw new UnsupportedOperationException(); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { throw new UnsupportedOperationException(); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { throw new UnsupportedOperationException(); } @Override public void setTransactionIsolation(int level) throws SQLException { this.transactionIsolation = level; } @Override public int getTransactionIsolation() throws SQLException { checkClosed(); return transactionIsolation; } /** * 暂时实现为isClosed */ @Override public boolean isValid(int timeout) throws SQLException { return this.isClosed(); } @Override public void setHoldability(int holdability) throws SQLException { /* * 如果你看到这里,那么恭喜,哈哈 mysql默认在5.x的jdbc driver里面也没有实现holdability 。 * 所以默认都是.CLOSE_CURSORS_AT_COMMIT 为了简化起见,我们也就只实现close这种 */ throw new UnsupportedOperationException("setHoldability"); } @Override public int getHoldability() throws SQLException { return ResultSet.CLOSE_CURSORS_AT_COMMIT; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return this.getClass().isAssignableFrom(iface); } @Override public <T> T unwrap(Class<T> iface) throws SQLException { try { return (T) this; } catch (Exception e) { throw new SQLException(e); } } public boolean removeStatement(Object arg0) { return openedStatements.remove(arg0); } public ExecutionContext getExecutionContext() { return this.executionContext; } @Override public SQLWarning getWarnings() throws SQLException { return null; } @Override public void clearWarnings() throws SQLException { // do nothing } @Override public void setReadOnly(boolean readOnly) throws SQLException { // do nothing } /** * 保持可读可写 */ @Override public boolean isReadOnly() throws SQLException { return false; } /*---------------------后面是未实现的方法------------------------------*/ @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 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 Map<String, Class<?>> getTypeMap() throws SQLException { throw new UnsupportedOperationException("getTypeMap"); } @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException { throw new UnsupportedOperationException("setTypeMap"); } @Override public String nativeSQL(String sql) throws SQLException { throw new UnsupportedOperationException("nativeSQL"); } @Override public void setCatalog(String catalog) throws SQLException { throw new UnsupportedOperationException("setCatalog"); } @Override public String getCatalog() throws SQLException { throw new UnsupportedOperationException("getCatalog"); } }