/*
* 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.alibaba.druid.pool;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantLock;
import javax.sql.ConnectionEventListener;
import javax.sql.StatementEventListener;
import com.alibaba.druid.pool.DruidAbstractDataSource.PhysicalConnectionInfo;
import com.alibaba.druid.proxy.jdbc.WrapperProxy;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.druid.util.JdbcUtils;
import com.alibaba.druid.util.Utils;
/**
* @author wenshao [szujobs@hotmail.com]
*/
public final class DruidConnectionHolder {
private final static Log LOG = LogFactory.getLog(DruidConnectionHolder.class);
private final DruidAbstractDataSource dataSource;
private final long connectionId;
private final Connection conn;
private final List<ConnectionEventListener> connectionEventListeners = new CopyOnWriteArrayList<ConnectionEventListener>();
private final List<StatementEventListener> statementEventListeners = new CopyOnWriteArrayList<StatementEventListener>();
protected final long connectTimeMillis;
protected transient long lastActiveTimeMillis;
private long useCount = 0;
private long keepAliveCheckCount = 0;
private long lastNotEmptyWaitNanos;
private final long createNanoSpan;
private PreparedStatementPool statementPool;
private final List<Statement> statementTrace = new ArrayList<Statement>(2);
private final boolean defaultReadOnly;
private final int defaultHoldability;
private final int defaultTransactionIsolation;
private final boolean defaultAutoCommit;
private boolean underlyingReadOnly;
private int underlyingHoldability;
private int underlyingTransactionIsolation;
private boolean underlyingAutoCommit;
private boolean discard = false;
protected final Map<String, Object> variables;
protected final Map<String, Object> globleVariables;
public static boolean holdabilityUnsupported = false;
public DruidConnectionHolder(DruidAbstractDataSource dataSource, PhysicalConnectionInfo pyConnectInfo)
throws SQLException{
this(dataSource,
pyConnectInfo.getPhysicalConnection(),
pyConnectInfo.getConnectNanoSpan(),
pyConnectInfo.getVairiables(),
pyConnectInfo.getGlobalVairiables());
}
public DruidConnectionHolder(DruidAbstractDataSource dataSource, Connection conn, long connectNanoSpan)
throws SQLException{
this(dataSource, conn, connectNanoSpan, null, null);
}
public DruidConnectionHolder(DruidAbstractDataSource dataSource, Connection conn, long connectNanoSpan,
Map<String, Object> variables, Map<String, Object> globleVariables)
throws SQLException{
this.dataSource = dataSource;
this.conn = conn;
this.createNanoSpan = connectNanoSpan;
this.variables = variables;
this.globleVariables = globleVariables;
this.connectTimeMillis = System.currentTimeMillis();
this.lastActiveTimeMillis = connectTimeMillis;
this.underlyingAutoCommit = conn.getAutoCommit();
if (conn instanceof WrapperProxy) {
this.connectionId = ((WrapperProxy) conn).getId();
} else {
this.connectionId = dataSource.createConnectionId();
}
{
boolean initUnderlyHoldability = !holdabilityUnsupported;
if (JdbcConstants.SYBASE.equals(dataSource.dbType) //
|| JdbcConstants.DB2.equals(dataSource.dbType) //
|| JdbcConstants.HIVE.equals(dataSource.dbType) //
) {
initUnderlyHoldability = false;
}
if (initUnderlyHoldability) {
try {
this.underlyingHoldability = conn.getHoldability();
} catch (UnsupportedOperationException e) {
holdabilityUnsupported = true;
LOG.warn("getHoldability unsupported", e);
} catch (SQLFeatureNotSupportedException e) {
holdabilityUnsupported = true;
LOG.warn("getHoldability unsupported", e);
} catch (SQLException e) {
// bug fixed for hive jdbc-driver
if ("Method not supported".equals(e.getMessage())) {
holdabilityUnsupported = true;
}
LOG.warn("getHoldability error", e);
}
}
}
this.underlyingReadOnly = conn.isReadOnly();
try {
this.underlyingTransactionIsolation = conn.getTransactionIsolation();
} catch (SQLException e) {
// compartible for alibaba corba
if ("HY000".equals(e.getSQLState())
|| "com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException".equals(e.getClass().getName())) {
// skip
} else {
throw e;
}
}
this.defaultHoldability = underlyingHoldability;
this.defaultTransactionIsolation = underlyingTransactionIsolation;
this.defaultAutoCommit = underlyingAutoCommit;
this.defaultReadOnly = underlyingReadOnly;
}
public boolean isUnderlyingReadOnly() {
return underlyingReadOnly;
}
public void setUnderlyingReadOnly(boolean underlyingReadOnly) {
this.underlyingReadOnly = underlyingReadOnly;
}
public int getUnderlyingHoldability() {
return underlyingHoldability;
}
public void setUnderlyingHoldability(int underlyingHoldability) {
this.underlyingHoldability = underlyingHoldability;
}
public int getUnderlyingTransactionIsolation() {
return underlyingTransactionIsolation;
}
public void setUnderlyingTransactionIsolation(int underlyingTransactionIsolation) {
this.underlyingTransactionIsolation = underlyingTransactionIsolation;
}
public boolean isUnderlyingAutoCommit() {
return underlyingAutoCommit;
}
public void setUnderlyingAutoCommit(boolean underlyingAutoCommit) {
this.underlyingAutoCommit = underlyingAutoCommit;
}
public long getLastActiveTimeMillis() {
return lastActiveTimeMillis;
}
public void setLastActiveTimeMillis(long lastActiveMillis) {
this.lastActiveTimeMillis = lastActiveMillis;
}
public void addTrace(DruidPooledStatement stmt) {
statementTrace.add(stmt);
}
public void removeTrace(DruidPooledStatement stmt) {
statementTrace.remove(stmt);
}
public List<ConnectionEventListener> getConnectionEventListeners() {
return connectionEventListeners;
}
public List<StatementEventListener> getStatementEventListeners() {
return statementEventListeners;
}
public PreparedStatementPool getStatementPool() {
if (statementPool == null) {
statementPool = new PreparedStatementPool(this);
}
return statementPool;
}
public PreparedStatementPool getStatementPoolDirect() {
return statementPool;
}
public void clearStatementCache() {
if (this.statementPool == null) {
return;
}
this.statementPool.clear();
}
public DruidAbstractDataSource getDataSource() {
return dataSource;
}
public boolean isPoolPreparedStatements() {
return dataSource.isPoolPreparedStatements();
}
public Connection getConnection() {
return conn;
}
public long getTimeMillis() {
return connectTimeMillis;
}
public long getUseCount() {
return useCount;
}
public long getConnectionId() {
return connectionId;
}
public void incrementUseCount() {
useCount++;
}
public long getKeepAliveCheckCount() {
return keepAliveCheckCount;
}
public void incrementKeepAliveCheckCount() {
keepAliveCheckCount++;
}
public void reset() throws SQLException {
// reset default settings
if (underlyingReadOnly != defaultReadOnly) {
conn.setReadOnly(defaultReadOnly);
underlyingReadOnly = defaultReadOnly;
}
if (underlyingHoldability != defaultHoldability) {
conn.setHoldability(defaultHoldability);
underlyingHoldability = defaultHoldability;
}
if (underlyingTransactionIsolation != defaultTransactionIsolation) {
conn.setTransactionIsolation(defaultTransactionIsolation);
underlyingTransactionIsolation = defaultTransactionIsolation;
}
if (underlyingAutoCommit != defaultAutoCommit) {
conn.setAutoCommit(defaultAutoCommit);
underlyingAutoCommit = defaultAutoCommit;
}
connectionEventListeners.clear();
statementEventListeners.clear();
for (Object item : statementTrace.toArray()) {
Statement stmt = (Statement) item;
JdbcUtils.close(stmt);
}
statementTrace.clear();
conn.clearWarnings();
}
public boolean isDiscard() {
return discard;
}
public void setDiscard(boolean discard) {
this.discard = discard;
}
public long getCreateNanoSpan() {
return createNanoSpan;
}
public long getLastNotEmptyWaitNanos() {
return lastNotEmptyWaitNanos;
}
protected void setLastNotEmptyWaitNanos(long lastNotEmptyWaitNanos) {
this.lastNotEmptyWaitNanos = lastNotEmptyWaitNanos;
}
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("{ID:");
buf.append(System.identityHashCode(conn));
buf.append(", ConnectTime:\"");
buf.append(Utils.toString(new Date(this.connectTimeMillis)));
buf.append("\", UseCount:");
buf.append(useCount);
if (lastActiveTimeMillis > 0) {
buf.append(", LastActiveTime:\"");
buf.append(Utils.toString(new Date(this.lastActiveTimeMillis)));
buf.append("\"");
}
if (statementPool != null && statementPool.getMap().size() > 0) {
buf.append("\", CachedStatementCount:");
buf.append(statementPool.getMap().size());
}
buf.append("}");
return buf.toString();
}
}