/* * Copyright 1999-2017 Alibaba Group Holding Ltd. * * 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. */ package com.fr.third.alibaba.druid.pool; import com.fr.third.alibaba.druid.filter.Filter; import com.fr.third.alibaba.druid.filter.FilterChainImpl; import com.fr.third.alibaba.druid.proxy.jdbc.TransactionInfo; import com.fr.third.alibaba.druid.support.logging.Log; import com.fr.third.alibaba.druid.support.logging.LogFactory; import javax.sql.ConnectionEvent; import javax.sql.ConnectionEventListener; import javax.sql.StatementEventListener; 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.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; import java.util.concurrent.locks.ReentrantLock; /** * @author wenshao [szujobs@hotmail.com] */ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.PooledConnection, Connection { private final static Log LOG = LogFactory.getLog(DruidPooledConnection.class); public static final int MAX_RECORD_SQL_COUNT = 10; protected Connection conn; protected volatile DruidConnectionHolder holder; protected TransactionInfo transactionInfo; private final boolean dupCloseLogEnable; private volatile boolean traceEnable = false; private boolean disable = false; private boolean closed = false; private final Thread ownerThread; private long connectedTimeMillis; private long connectedTimeNano; private volatile boolean running = false; private volatile boolean abandoned = false; private StackTraceElement[] connectStackTrace; private Throwable disableError = null; public ReentrantLock lock = new ReentrantLock(); public DruidPooledConnection(DruidConnectionHolder holder){ super(holder.getConnection()); this.conn = holder.getConnection(); this.holder = holder; dupCloseLogEnable = holder.getDataSource().isDupCloseLogEnable(); ownerThread = Thread.currentThread(); connectedTimeMillis = System.currentTimeMillis(); } public long getConnectedTimeMillis() { return connectedTimeMillis; } public Thread getOwnerThread() { return ownerThread; } public StackTraceElement[] getConnectStackTrace() { return connectStackTrace; } public void setConnectStackTrace(StackTraceElement[] connectStackTrace) { this.connectStackTrace = connectStackTrace; } public long getConnectedTimeNano() { return connectedTimeNano; } public void setConnectedTimeNano() { if (connectedTimeNano <= 0) { this.setConnectedTimeNano(System.nanoTime()); } } public void setConnectedTimeNano(long connectedTimeNano) { this.connectedTimeNano = connectedTimeNano; } public boolean isTraceEnable() { return traceEnable; } public void setTraceEnable(boolean traceEnable) { this.traceEnable = traceEnable; } public SQLException handleException(Throwable t) throws SQLException { final DruidConnectionHolder holder = this.holder; // if (holder != null) { DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.handleConnectionException(this, t); } if (t instanceof SQLException) { throw (SQLException) t; } throw new SQLException("Error", t); } public boolean isOracle() { return holder.getDataSource().isOracle(); } public void closePoolableStatement(DruidPooledPreparedStatement stmt) throws SQLException { PreparedStatement rawStatement = stmt.getRawPreparedStatement(); if (holder == null) { return; } if (stmt.isPooled()) { try { rawStatement.clearParameters(); } catch (SQLException ex) { this.handleException(ex); if (rawStatement.getConnection().isClosed()) { return; } LOG.error("clear parameter error", ex); } } stmt.getPreparedStatementHolder().decrementInUseCount(); if (stmt.isPooled() && holder.isPoolPreparedStatements() && stmt.exceptionCount == 0) { holder.getStatementPool().put(stmt.getPreparedStatementHolder()); stmt.clearResultSet(); holder.removeTrace(stmt); stmt.getPreparedStatementHolder().setFetchRowPeak(stmt.getFetchRowPeak()); stmt.setClosed(true); // soft set close } else if (stmt.isPooled() && holder.isPoolPreparedStatements()) { // the PreparedStatement threw an exception stmt.clearResultSet(); holder.removeTrace(stmt); holder.getStatementPool().remove(stmt.getPreparedStatementHolder()); } else { try { //Connection behind the statement may be in invalid state, which will throw a SQLException. //In this case, the exception is desired to be properly handled to remove the unusable connection from the pool. stmt.closeInternal(); } catch (SQLException ex) { this.handleException(ex); throw ex; } finally { holder.getDataSource().incrementClosedPreparedStatementCount(); } } } public DruidConnectionHolder getConnectionHolder() { return holder; } @Override public Connection getConnection() { return conn; } public void disable() { disable(null); } public void disable(Throwable error) { if (this.holder != null) { this.holder.clearStatementCache(); } this.traceEnable = false; this.holder = null; this.transactionInfo = null; this.disable = true; this.disableError = error; } public boolean isDisable() { return disable; } @Override public void close() throws SQLException { if (this.disable) { return; } DruidConnectionHolder holder = this.holder; if (holder == null) { if (dupCloseLogEnable) { LOG.error("dup close"); } return; } DruidAbstractDataSource dataSource = holder.getDataSource(); boolean isSameThread = this.getOwnerThread() == Thread.currentThread(); if (!isSameThread) { dataSource.setAsyncCloseConnectionEnable(true); } if (dataSource.isAsyncCloseConnectionEnable()) { syncClose(); return; } for (ConnectionEventListener listener : holder.getConnectionEventListeners()) { listener.connectionClosed(new ConnectionEvent(this)); } List filters = dataSource.getProxyFilters(); if (filters.size() > 0) { FilterChainImpl filterChain = new FilterChainImpl(dataSource); filterChain.dataSource_recycle(this); } else { recycle(); } this.disable = true; } public void syncClose() throws SQLException { lock.lock(); try { if (this.disable) { return; } DruidConnectionHolder holder = this.holder; if (holder == null) { if (dupCloseLogEnable) { LOG.error("dup close"); } return; } for (ConnectionEventListener listener : holder.getConnectionEventListeners()) { listener.connectionClosed(new ConnectionEvent(this)); } DruidAbstractDataSource dataSource = holder.getDataSource(); List filters = dataSource.getProxyFilters(); if (filters.size() > 0) { FilterChainImpl filterChain = new FilterChainImpl(dataSource); filterChain.dataSource_recycle(this); } else { recycle(); } this.disable = true; } finally { lock.unlock(); } } public void recycle() throws SQLException { if (this.disable) { return; } DruidConnectionHolder holder = this.holder; if (holder == null) { if (dupCloseLogEnable) { LOG.error("dup close"); } return; } if (!this.abandoned) { DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.recycle(this); } this.holder = null; conn = null; transactionInfo = null; closed = true; } // //////////////////// @Override public PreparedStatement prepareStatement(String sql) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; DruidPooledPreparedStatement.PreparedStatementKey key = new DruidPooledPreparedStatement.PreparedStatementKey(sql, getCatalog(), PreparedStatementPool.MethodType.M1); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } private void initStatement(PreparedStatementHolder stmtHolder) throws SQLException { stmtHolder.incrementInUseCount(); holder.getDataSource().initStatement(this, stmtHolder.statement); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; DruidPooledPreparedStatement.PreparedStatementKey key = new DruidPooledPreparedStatement.PreparedStatementKey(sql, getCatalog(), PreparedStatementPool.MethodType.M2, resultSetType, resultSetConcurrency); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, resultSetType, resultSetConcurrency)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; DruidPooledPreparedStatement.PreparedStatementKey key = new DruidPooledPreparedStatement.PreparedStatementKey(sql, getCatalog(), PreparedStatementPool.MethodType.M3, resultSetType, resultSetConcurrency, resultSetHoldability); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { checkState(); DruidPooledPreparedStatement.PreparedStatementKey key = new DruidPooledPreparedStatement.PreparedStatementKey(sql, getCatalog(), PreparedStatementPool.MethodType.M4, columnIndexes); PreparedStatementHolder stmtHolder = null; boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnIndexes)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { checkState(); DruidPooledPreparedStatement.PreparedStatementKey key = new DruidPooledPreparedStatement.PreparedStatementKey(sql, getCatalog(), PreparedStatementPool.MethodType.M5, columnNames); PreparedStatementHolder stmtHolder = null; boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnNames)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { checkState(); DruidPooledPreparedStatement.PreparedStatementKey key = new DruidPooledPreparedStatement.PreparedStatementKey(sql, getCatalog(), PreparedStatementPool.MethodType.M6, autoGeneratedKeys); PreparedStatementHolder stmtHolder = null; boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, autoGeneratedKeys)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } // //////////////////// @Override public CallableStatement prepareCall(String sql) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; DruidPooledPreparedStatement.PreparedStatementKey key = new DruidPooledPreparedStatement.PreparedStatementKey(sql, getCatalog(), PreparedStatementPool.MethodType.Precall_1); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; DruidPooledPreparedStatement.PreparedStatementKey key = new DruidPooledPreparedStatement.PreparedStatementKey(sql, getCatalog(), PreparedStatementPool.MethodType.Precall_2, resultSetType, resultSetConcurrency, resultSetHoldability); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { checkState(); PreparedStatementHolder stmtHolder = null; DruidPooledPreparedStatement.PreparedStatementKey key = new DruidPooledPreparedStatement.PreparedStatementKey(sql, getCatalog(), PreparedStatementPool.MethodType.Precall_3, resultSetType, resultSetConcurrency); boolean poolPreparedStatements = holder.isPoolPreparedStatements(); if (poolPreparedStatements) { stmtHolder = holder.getStatementPool().get(key); } if (stmtHolder == null) { try { stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql, resultSetType, resultSetConcurrency)); holder.getDataSource().incrementPreparedStatementCount(); } catch (SQLException ex) { handleException(ex); } } initStatement(stmtHolder); DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder); holder.addTrace(rtnVal); return rtnVal; } // //////////////////// @Override public Statement createStatement() throws SQLException { checkState(); Statement stmt = null; try { stmt = conn.createStatement(); } catch (SQLException ex) { handleException(ex); } holder.getDataSource().initStatement(this, stmt); DruidPooledStatement poolableStatement = new DruidPooledStatement(this, stmt); holder.addTrace(poolableStatement); return poolableStatement; } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { checkState(); Statement stmt = null; try { stmt = conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); } catch (SQLException ex) { handleException(ex); } holder.getDataSource().initStatement(this, stmt); DruidPooledStatement poolableStatement = new DruidPooledStatement(this, stmt); holder.addTrace(poolableStatement); return poolableStatement; } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { checkState(); Statement stmt = null; try { stmt = conn.createStatement(resultSetType, resultSetConcurrency); } catch (SQLException ex) { handleException(ex); } holder.getDataSource().initStatement(this, stmt); DruidPooledStatement poolableStatement = new DruidPooledStatement(this, stmt); holder.addTrace(poolableStatement); return poolableStatement; } @Override public String nativeSQL(String sql) throws SQLException { checkState(); return conn.nativeSQL(sql); } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { checkState(); boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState(); if (useLocalSessionState) { if (autoCommit == holder.isUnderlyingAutoCommit()) { return; } } try { conn.setAutoCommit(autoCommit); holder.setUnderlyingAutoCommit(autoCommit); } catch (SQLException ex) { handleException(ex); } } protected void transactionRecord(String sql) throws SQLException { if (transactionInfo == null && (!conn.getAutoCommit())) { DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.incrementStartTransactionCount(); transactionInfo = new TransactionInfo(dataSource.createTransactionId()); } if (transactionInfo != null) { List sqlList = transactionInfo.getSqlList(); if (sqlList.size() < MAX_RECORD_SQL_COUNT) { sqlList.add(sql); } } } @Override public boolean getAutoCommit() throws SQLException { checkState(); return conn.getAutoCommit(); } @Override public void commit() throws SQLException { checkState(); DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.incrementCommitCount(); try { conn.commit(); } catch (SQLException ex) { handleException(ex); } finally { handleEndTransaction(dataSource, null); } } public TransactionInfo getTransactionInfo() { return transactionInfo; } @Override public void rollback() throws SQLException { if (transactionInfo == null) { return; } if (holder == null) { return; } DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.incrementRollbackCount(); try { conn.rollback(); } catch (SQLException ex) { handleException(ex); } finally { handleEndTransaction(dataSource, null); } } @Override public Savepoint setSavepoint(String name) throws SQLException { checkState(); try { return conn.setSavepoint(name); } catch (SQLException ex) { handleException(ex); return null; // never arrive } } @Override public void rollback(Savepoint savepoint) throws SQLException { if (holder == null) { return; } DruidAbstractDataSource dataSource = holder.getDataSource(); dataSource.incrementRollbackCount(); try { conn.rollback(savepoint); } catch (SQLException ex) { handleException(ex); } finally { handleEndTransaction(dataSource, savepoint); } } private void handleEndTransaction(DruidAbstractDataSource dataSource, Savepoint savepoint) { if (transactionInfo != null && savepoint == null) { transactionInfo.setEndTimeMillis(); long transactionMillis = transactionInfo.getEndTimeMillis() - transactionInfo.getStartTimeMillis(); dataSource.getTransactionHistogram().record(transactionMillis); dataSource.logTransaction(transactionInfo); transactionInfo = null; } } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { checkState(); try { conn.releaseSavepoint(savepoint); } catch (SQLException ex) { handleException(ex); } } @Override public Clob createClob() throws SQLException { checkState(); try { return conn.createClob(); } catch (SQLException ex) { handleException(ex); return null; // never arrive } } @Override public boolean isClosed() throws SQLException { if (holder == null) { return true; } return conn.isClosed(); } public boolean isAbandonded() { return this.abandoned; } @Override public DatabaseMetaData getMetaData() throws SQLException { checkState(); return conn.getMetaData(); } @Override public void setReadOnly(boolean readOnly) throws SQLException { checkState(); boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState(); if (useLocalSessionState) { if (readOnly == holder.isUnderlyingReadOnly()) { return; } } try { conn.setReadOnly(readOnly); } catch (SQLException ex) { handleException(ex); } holder.setUnderlyingReadOnly(readOnly); } @Override public boolean isReadOnly() throws SQLException { checkState(); return conn.isReadOnly(); } @Override public void setCatalog(String catalog) throws SQLException { checkState(); try { conn.setCatalog(catalog); } catch (SQLException ex) { handleException(ex); } } @Override public String getCatalog() throws SQLException { checkState(); return conn.getCatalog(); } @Override public void setTransactionIsolation(int level) throws SQLException { checkState(); boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState(); if (useLocalSessionState) { if (level == holder.getUnderlyingTransactionIsolation()) { return; } } try { conn.setTransactionIsolation(level); } catch (SQLException ex) { handleException(ex); } holder.setUnderlyingTransactionIsolation(level); } @Override public int getTransactionIsolation() throws SQLException { checkState(); return holder.getUnderlyingTransactionIsolation(); } @Override public SQLWarning getWarnings() throws SQLException { checkState(); return conn.getWarnings(); } @Override public void clearWarnings() throws SQLException { checkState(); try { conn.clearWarnings(); } catch (SQLException ex) { handleException(ex); } } @Override public Map> getTypeMap() throws SQLException { checkState(); return conn.getTypeMap(); } @Override public void setTypeMap(Map> map) throws SQLException { checkState(); conn.setTypeMap(map); } @Override public void setHoldability(int holdability) throws SQLException { checkState(); boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState(); if (useLocalSessionState) { if (holdability == holder.getUnderlyingHoldability()) { return; } } conn.setHoldability(holdability); holder.setUnderlyingHoldability(holdability); } @Override public int getHoldability() throws SQLException { checkState(); return conn.getHoldability(); } @Override public Savepoint setSavepoint() throws SQLException { checkState(); try { return conn.setSavepoint(); } catch (SQLException ex) { handleException(ex); return null; } } @Override public Blob createBlob() throws SQLException { checkState(); return conn.createBlob(); } @Override public NClob createNClob() throws SQLException { checkState(); return conn.createNClob(); } @Override public SQLXML createSQLXML() throws SQLException { checkState(); return conn.createSQLXML(); } @Override public boolean isValid(int timeout) throws SQLException { checkState(); return conn.isValid(timeout); } @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { if (holder == null) { throw new SQLClientInfoException(); } conn.setClientInfo(name, value); } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { if (holder == null) { throw new SQLClientInfoException(); } conn.setClientInfo(properties); } @Override public String getClientInfo(String name) throws SQLException { checkState(); return conn.getClientInfo(name); } @Override public Properties getClientInfo() throws SQLException { checkState(); return conn.getClientInfo(); } @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { checkState(); return conn.createArrayOf(typeName, elements); } @Override public Struct createStruct(String typeName, Object[] attributes) throws SQLException { checkState(); return conn.createStruct(typeName, attributes); } @Override public void addConnectionEventListener(ConnectionEventListener listener) { if (holder == null) { throw new IllegalStateException(); } holder.getConnectionEventListeners().add(listener); } @Override public void removeConnectionEventListener(ConnectionEventListener listener) { if (holder == null) { throw new IllegalStateException(); } holder.getConnectionEventListeners().remove(listener); } @Override public void addStatementEventListener(StatementEventListener listener) { if (holder == null) { throw new IllegalStateException(); } holder.getStatementEventListeners().add(listener); } @Override public void removeStatementEventListener(StatementEventListener listener) { if (holder == null) { throw new IllegalStateException(); } holder.getStatementEventListeners().remove(listener); } public Throwable getDisableError() { return disableError; } public void checkState() throws SQLException { final boolean asyncCloseEnabled; if (holder != null) { asyncCloseEnabled = holder.getDataSource().isAsyncCloseConnectionEnable(); } else { asyncCloseEnabled = false; } if (asyncCloseEnabled) { lock.lock(); try { checkStateInternal(); } finally { lock.unlock(); } } else { checkStateInternal(); } } private void checkStateInternal() throws SQLException { if (holder == null) { if (disableError != null) { throw new SQLException("connection holder is null", disableError); } else { throw new SQLException("connection holder is null"); } } if (closed) { if (disableError != null) { throw new SQLException("connection closed", disableError); } else { throw new SQLException("connection closed"); } } if (disable) { if (disableError != null) { throw new SQLException("connection disabled", disableError); } else { throw new SQLException("connection disabled"); } } } public String toString() { if (conn != null) { return conn.toString(); } else { return "closed-conn-" + System.identityHashCode(this); } } public void setSchema(String schema) throws SQLException { try { conn.setSchema(schema); } catch (Throwable e) { throw new SQLFeatureNotSupportedException(); } } public String getSchema() throws SQLException { try { return conn.getSchema(); }catch (Throwable e) { throw new SQLFeatureNotSupportedException(); } } public void abort(Executor executor) throws SQLException { try { conn.abort(executor); }catch (Throwable e) { throw new SQLFeatureNotSupportedException(); } } public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { try { conn.setNetworkTimeout(executor, milliseconds); }catch (Throwable e) { throw new SQLFeatureNotSupportedException(); } } public int getNetworkTimeout() throws SQLException { try { return conn.getNetworkTimeout(); }catch (Throwable e) { throw new SQLFeatureNotSupportedException(); } } final void beforeExecute() { final DruidConnectionHolder holder = this.holder; if (holder != null && holder.getDataSource().isRemoveAbandoned()) { running = true; } } final void afterExecute() { final DruidConnectionHolder holder = this.holder; if (holder != null && holder.getDataSource().isRemoveAbandoned()) { running = false; holder.setLastActiveTimeMillis(System.currentTimeMillis()); } } boolean isRunning() { return running; } public void abandond() { this.abandoned = true; } /** * @since 1.0.17 */ public long getPhysicalConnectNanoSpan() { return this.holder.getCreateNanoSpan(); } /** * @since 1.0.17 */ public long getPhysicalConnectionUsedCount() { return this.holder.getUseCount(); } /** * @since 1.0.17 */ public long getConnectNotEmptyWaitNanos() { return this.holder.getLastNotEmptyWaitNanos(); } /** * @since 1.0.28 */ public Map getVariables() { return this.holder.variables; } /** * @since 1.0.28 */ public Map getGloablVariables() { return this.holder.globleVariables; } }