diff --git a/src/main/java/com/alibaba/druid/filter/logging/LogFilter.java b/src/main/java/com/alibaba/druid/filter/logging/LogFilter.java index 4a7ae894d5..1412851959 100644 --- a/src/main/java/com/alibaba/druid/filter/logging/LogFilter.java +++ b/src/main/java/com/alibaba/druid/filter/logging/LogFilter.java @@ -1,827 +1,837 @@ -/* - * Copyright 1999-2011 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.filter.logging; - -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Savepoint; -import java.sql.Types; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import com.alibaba.druid.filter.FilterChain; -import com.alibaba.druid.filter.FilterEventAdapter; -import com.alibaba.druid.pool.DruidDataSource; -import com.alibaba.druid.pool.DruidPooledConnection; -import com.alibaba.druid.proxy.jdbc.CallableStatementProxy; -import com.alibaba.druid.proxy.jdbc.ConnectionProxy; -import com.alibaba.druid.proxy.jdbc.DataSourceProxy; -import com.alibaba.druid.proxy.jdbc.JdbcParameter; -import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy; -import com.alibaba.druid.proxy.jdbc.ResultSetProxy; -import com.alibaba.druid.proxy.jdbc.StatementProxy; -import com.alibaba.druid.sql.SQLUtils; -import com.alibaba.druid.util.JdbcUtils; - -/** - * @author wenshao - */ -public abstract class LogFilter extends FilterEventAdapter implements LogFilterMBean { - - protected String dataSourceLoggerName = "druid.sql.DataSource"; - protected String connectionLoggerName = "druid.sql.Connection"; - protected String statementLoggerName = "druid.sql.Statement"; - protected String resultSetLoggerName = "druid.sql.ResultSet"; - - private boolean connectionConnectBeforeLogEnable = true; - private boolean connectionConnectAfterLogEnable = true; - private boolean connectionCommitAfterLogEnable = true; - private boolean connectionRollbackAfterLogEnable = true; - private boolean connectionCloseAfterLogEnable = true; - - private boolean statementCreateAfterLogEnable = true; - private boolean statementPrepareAfterLogEnable = true; - private boolean statementPrepareCallAfterLogEnable = true; - - private boolean statementExecuteAfterLogEnable = true; - private boolean statementExecuteQueryAfterLogEnable = true; - private boolean statementExecuteUpdateAfterLogEnable = true; - private boolean statementExecuteBatchAfterLogEnable = true; - private boolean statementExecutableSqlLogEnable = false; - - private boolean statementCloseAfterLogEnable = true; - - private boolean statementParameterSetLogEnable = true; - - private boolean resultSetNextAfterLogEnable = true; - private boolean resultSetOpenAfterLogEnable = true; - private boolean resultSetCloseAfterLogEnable = true; - - private boolean dataSourceLogEnabled = true; - private boolean connectionLogEnabled = true; - private boolean connectionLogErrorEnabled = true; - private boolean statementLogEnabled = true; - private boolean statementLogErrorEnabled = true; - private boolean resultSetLogEnabled = true; - private boolean resultSetLogErrorEnabled = true; - - protected DataSourceProxy dataSource; - - public LogFilter(){ - { - String prop = System.getProperty("druid.log.stmt"); - if (prop == "false") { - statementLogEnabled = false; - } - } - { - String prop = System.getProperty("druid.log.rs"); - if (prop == "false") { - resultSetLogEnabled = false; - } - } - { - String prop = System.getProperty("druid.log.stmt.executableSql"); - if (prop == "true") { - statementExecutableSqlLogEnable = true; - } - } - } - - @Override - public void init(DataSourceProxy dataSource) { - this.dataSource = dataSource; - } - - public boolean isConnectionLogErrorEnabled() { - return connectionLogErrorEnabled; - } - - public boolean isResultSetCloseAfterLogEnabled() { - return isResultSetLogEnabled() && resultSetCloseAfterLogEnable; - } - - public void setResultSetCloseAfterLogEnabled(boolean resultSetCloseAfterLogEnable) { - this.resultSetCloseAfterLogEnable = resultSetCloseAfterLogEnable; - } - - public void setConnectionLogErrorEnabled(boolean connectionLogErrorEnabled) { - this.connectionLogErrorEnabled = connectionLogErrorEnabled; - } - - public boolean isResultSetLogErrorEnabled() { - return resultSetLogErrorEnabled; - } - - public void setResultSetLogErrorEnabled(boolean resultSetLogErrorEnabled) { - this.resultSetLogErrorEnabled = resultSetLogErrorEnabled; - } - - public boolean isConnectionConnectBeforeLogEnabled() { - return isConnectionLogEnabled() && connectionConnectBeforeLogEnable; - } - - public void setConnectionConnectBeforeLogEnabled(boolean beforeConnectionConnectLogEnable) { - this.connectionConnectBeforeLogEnable = beforeConnectionConnectLogEnable; - } - - public boolean isConnectionCloseAfterLogEnabled() { - return isConnectionLogEnabled() && connectionCloseAfterLogEnable; - } - - public boolean isConnectionRollbackAfterLogEnabled() { - return isConnectionLogEnabled() && connectionRollbackAfterLogEnable; - } - - public void setConnectionRollbackAfterLogEnabled(boolean connectionRollbackAfterLogEnable) { - this.connectionRollbackAfterLogEnable = connectionRollbackAfterLogEnable; - } - - public void setConnectionCloseAfterLogEnabled(boolean afterConnectionCloseLogEnable) { - this.connectionCloseAfterLogEnable = afterConnectionCloseLogEnable; - } - - public boolean isConnectionCommitAfterLogEnabled() { - return isConnectionLogEnabled() && connectionCommitAfterLogEnable; - } - - public void setConnectionCommitAfterLogEnabled(boolean afterConnectionCommitLogEnable) { - this.connectionCommitAfterLogEnable = afterConnectionCommitLogEnable; - } - - public boolean isConnectionConnectAfterLogEnabled() { - return isConnectionLogEnabled() && connectionConnectAfterLogEnable; - } - - public void setConnectionConnectAfterLogEnabled(boolean afterConnectionConnectLogEnable) { - this.connectionConnectAfterLogEnable = afterConnectionConnectLogEnable; - } - - public boolean isResultSetNextAfterLogEnabled() { - return isResultSetLogEnabled() && resultSetNextAfterLogEnable; - } - - public void setResultSetNextAfterLogEnabled(boolean afterResultSetNextLogEnable) { - this.resultSetNextAfterLogEnable = afterResultSetNextLogEnable; - } - - public boolean isResultSetOpenAfterLogEnabled() { - return isResultSetLogEnabled() && resultSetOpenAfterLogEnable; - } - - public void setResultSetOpenAfterLogEnabled(boolean afterResultSetOpenLogEnable) { - this.resultSetOpenAfterLogEnable = afterResultSetOpenLogEnable; - } - - public boolean isStatementCloseAfterLogEnabled() { - return isStatementLogEnabled() && statementCloseAfterLogEnable; - } - - public void setStatementCloseAfterLogEnabled(boolean afterStatementCloseLogEnable) { - this.statementCloseAfterLogEnable = afterStatementCloseLogEnable; - } - - public boolean isStatementCreateAfterLogEnabled() { - return isStatementLogEnabled() && statementCreateAfterLogEnable; - } - - public void setStatementCreateAfterLogEnabled(boolean afterStatementCreateLogEnable) { - this.statementCreateAfterLogEnable = afterStatementCreateLogEnable; - } - - public boolean isStatementExecuteBatchAfterLogEnabled() { - return isStatementLogEnabled() && statementExecuteBatchAfterLogEnable; - } - - public void setStatementExecuteBatchAfterLogEnabled(boolean afterStatementExecuteBatchLogEnable) { - this.statementExecuteBatchAfterLogEnable = afterStatementExecuteBatchLogEnable; - } - - public boolean isStatementExecuteAfterLogEnabled() { - return isStatementLogEnabled() && statementExecuteAfterLogEnable; - } - - public void setStatementExecuteAfterLogEnabled(boolean afterStatementExecuteLogEnable) { - this.statementExecuteAfterLogEnable = afterStatementExecuteLogEnable; - } - - public boolean isStatementExecuteQueryAfterLogEnabled() { - return isStatementLogEnabled() && statementExecuteQueryAfterLogEnable; - } - - public void setStatementExecuteQueryAfterLogEnabled(boolean afterStatementExecuteQueryLogEnable) { - this.statementExecuteQueryAfterLogEnable = afterStatementExecuteQueryLogEnable; - } - - public boolean isStatementExecuteUpdateAfterLogEnabled() { - return isStatementLogEnabled() && statementExecuteUpdateAfterLogEnable; - } - - public void setStatementExecuteUpdateAfterLogEnabled(boolean afterStatementExecuteUpdateLogEnable) { - this.statementExecuteUpdateAfterLogEnable = afterStatementExecuteUpdateLogEnable; - } - - public boolean isStatementExecutableSqlLogEnable() { - return statementExecutableSqlLogEnable; - } - - public void setStatementExecutableSqlLogEnable(boolean statementExecutableSqlLogEnable) { - this.statementExecutableSqlLogEnable = statementExecutableSqlLogEnable; - } - - public boolean isStatementPrepareCallAfterLogEnabled() { - return isStatementLogEnabled() && statementPrepareCallAfterLogEnable; - } - - public void setStatementPrepareCallAfterLogEnabled(boolean afterStatementPrepareCallLogEnable) { - this.statementPrepareCallAfterLogEnable = afterStatementPrepareCallLogEnable; - } - - public boolean isStatementPrepareAfterLogEnabled() { - return isStatementLogEnabled() && statementPrepareAfterLogEnable; - } - - public void setStatementPrepareAfterLogEnabled(boolean afterStatementPrepareLogEnable) { - this.statementPrepareAfterLogEnable = afterStatementPrepareLogEnable; - } - - public boolean isDataSourceLogEnabled() { - return dataSourceLogEnabled; - } - - public void setDataSourceLogEnabled(boolean dataSourceLogEnabled) { - this.dataSourceLogEnabled = dataSourceLogEnabled; - } - - public boolean isConnectionLogEnabled() { - return connectionLogEnabled; - } - - public void setConnectionLogEnabled(boolean connectionLogEnabled) { - this.connectionLogEnabled = connectionLogEnabled; - } - - public boolean isStatementLogEnabled() { - return statementLogEnabled; - } - - public void setStatementLogEnabled(boolean statementLogEnabled) { - this.statementLogEnabled = statementLogEnabled; - } - - public boolean isStatementLogErrorEnabled() { - return statementLogErrorEnabled; - } - - public void setStatementLogErrorEnabled(boolean statementLogErrorEnabled) { - this.statementLogErrorEnabled = statementLogErrorEnabled; - } - - public boolean isResultSetLogEnabled() { - return resultSetLogEnabled; - } - - public void setResultSetLogEnabled(boolean resultSetLogEnabled) { - this.resultSetLogEnabled = resultSetLogEnabled; - } - - public boolean isStatementParameterSetLogEnabled() { - return isStatementLogEnabled() && statementParameterSetLogEnable; - } - - public void setStatementParameterSetLogEnabled(boolean statementParameterSetLogEnable) { - this.statementParameterSetLogEnable = statementParameterSetLogEnable; - } - - protected abstract void connectionLog(String message); - - protected abstract void statementLog(String message); - - protected abstract void statementLogError(String message, Throwable error); - - protected abstract void resultSetLog(String message); - - protected abstract void resultSetLogError(String message, Throwable error); - - public void connection_connectAfter(ConnectionProxy connection) { - if (connectionConnectAfterLogEnable && isConnectionLogEnabled()) { - connectionLog("{conn-" + connection.getId() + "} connected"); - } - } - - @Override - public Savepoint connection_setSavepoint(FilterChain chain, ConnectionProxy connection) throws SQLException { - - Savepoint savepoint = chain.connection_setSavepoint(connection); - - if (isConnectionLogEnabled()) { - connectionLog("{conn " + connection.getId() + "} setSavepoint-" + savepoint.getSavepointId()); - } - - return savepoint; - } - - @Override - public Savepoint connection_setSavepoint(FilterChain chain, ConnectionProxy connection, String name) - throws SQLException { - Savepoint savepoint = chain.connection_setSavepoint(connection, name); - - if (isConnectionLogEnabled()) { - connectionLog("{conn " + connection.getId() + "} setSavepoint-" + name); - } - - return savepoint; - } - - @Override - public void connection_rollback(FilterChain chain, ConnectionProxy connection) throws SQLException { - super.connection_rollback(chain, connection); - - if (connectionRollbackAfterLogEnable && isConnectionLogEnabled()) { - connectionLog("{conn " + connection.getId() + "} rollback"); - } - } - - @Override - public void connection_rollback(FilterChain chain, ConnectionProxy connection, Savepoint savePoint) - throws SQLException { - super.connection_rollback(chain, connection, savePoint); - - if (connectionRollbackAfterLogEnable && isConnectionLogEnabled()) { - connectionLog("{conn " + connection.getId() + "} rollback -> " + savePoint.getSavepointId()); - } - } - - @Override - public void connection_commit(FilterChain chain, ConnectionProxy connection) throws SQLException { - super.connection_commit(chain, connection); - - if (connectionCommitAfterLogEnable && isConnectionLogEnabled()) { - connectionLog("{conn-" + connection.getId() + "} commited"); - } - } - - @Override - public void connection_setAutoCommit(FilterChain chain, ConnectionProxy connection, boolean autoCommit) - throws SQLException { - - connectionLog("{conn-" + connection.getId() + "} setAutoCommit " + autoCommit); - chain.connection_setAutoCommit(connection, autoCommit); - } - - @Override - public void connection_close(FilterChain chain, ConnectionProxy connection) throws SQLException { - super.connection_close(chain, connection); - - if (connectionCloseAfterLogEnable && isConnectionLogEnabled()) { - connectionLog("{conn-" + connection.getId() + "} closed"); - } - } - - @Override - public void statement_close(FilterChain chain, StatementProxy statement) throws SQLException { - super.statement_close(chain, statement); - - if (statementCloseAfterLogEnable && isStatementLogEnabled()) { - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} closed"); - } - } - - @Override - protected void statementExecuteBefore(StatementProxy statement, String sql) { - statement.setLastExecuteStartNano(); - if (statement instanceof PreparedStatementProxy) { - logParameter((PreparedStatementProxy) statement); - } - } - - @Override - protected void statementExecuteAfter(StatementProxy statement, String sql, boolean firstResult) { - logExecutableSql(statement, sql); - - if (statementExecuteAfterLogEnable && isStatementLogEnabled()) { - statement.setLastExecuteTimeNano(); - double nanos = statement.getLastExecuteTimeNano(); - double millis = nanos / (1000 * 1000); - - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. " - + millis + " millis. " + sql); - } - } - - @Override - protected void statementExecuteBatchBefore(StatementProxy statement) { - statement.setLastExecuteStartNano(); - } - - @Override - protected void statementExecuteBatchAfter(StatementProxy statement, int[] result) { - String sql; - if (statement instanceof PreparedStatementProxy) { - sql = ((PreparedStatementProxy) statement).getSql(); - } else { - sql = statement.getBatchSql(); - } - - logExecutableSql(statement, sql); - - if (statementExecuteBatchAfterLogEnable && isStatementLogEnabled()) { - statement.setLastExecuteTimeNano(); - double nanos = statement.getLastExecuteTimeNano(); - double millis = nanos / (1000 * 1000); - - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) - + "} batch executed. " + millis + " millis. " + sql); - } - } - - @Override - protected void statementExecuteQueryBefore(StatementProxy statement, String sql) { - statement.setLastExecuteStartNano(); - if (statement instanceof PreparedStatementProxy) { - logParameter((PreparedStatementProxy) statement); - } - } - - @Override - protected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) { - logExecutableSql(statement, sql); - - if (statementExecuteQueryAfterLogEnable && isStatementLogEnabled()) { - statement.setLastExecuteTimeNano(); - double nanos = statement.getLastExecuteTimeNano(); - double millis = nanos / (1000 * 1000); - - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + ", rs-" - + resultSet.getId() + "} query executed. " + millis + " millis. " + sql); - } - } - - @Override - protected void statementExecuteUpdateBefore(StatementProxy statement, String sql) { - statement.setLastExecuteStartNano(); - if (statement instanceof PreparedStatementProxy) { - logParameter((PreparedStatementProxy) statement); - } - } - - @Override - protected void statementExecuteUpdateAfter(StatementProxy statement, String sql, int updateCount) { - logExecutableSql(statement, sql); - - if (statementExecuteUpdateAfterLogEnable && isStatementLogEnabled()) { - statement.setLastExecuteTimeNano(); - double nanos = statement.getLastExecuteTimeNano(); - double millis = nanos / (1000 * 1000); - - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) - + "} update executed. effort " + updateCount + ". " + millis + " millis. " + sql); - } - } - - private void logExecutableSql(StatementProxy statement, String sql) { - if (!isStatementExecutableSqlLogEnable()) { - return; - } - - Map parameterMap = statement.getParameters(); - if (parameterMap == null || parameterMap.size() == 0) { - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. " - + sql); - return; - } - - List parameters = new ArrayList(parameterMap.size()); - for (JdbcParameter jdbcParam : parameterMap.values()) { - parameters.add(jdbcParam.getValue()); - } - - String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); - String formattedSql = SQLUtils.format(sql, dbType, parameters); - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. " - + formattedSql); - } - - @Override - public void resultSet_close(FilterChain chain, ResultSetProxy resultSet) throws SQLException { - chain.resultSet_close(resultSet); - - StringBuffer buf = new StringBuffer(); - buf.append("{conn-"); - buf.append(resultSet.getStatementProxy().getConnectionProxy().getId()); - buf.append(", "); - buf.append(stmtId(resultSet)); - buf.append(", rs-"); - buf.append(resultSet.getId()); - buf.append("} closed"); - - if (isResultSetCloseAfterLogEnabled()) { - resultSetLog(buf.toString()); - } - } - - @Override - public boolean resultSet_next(FilterChain chain, ResultSetProxy resultSet) throws SQLException { - boolean moreRows = super.resultSet_next(chain, resultSet); - - if (moreRows) { - if (resultSetNextAfterLogEnable && isResultSetLogEnabled()) { - try { - StringBuffer buf = new StringBuffer(); - buf.append("{conn-"); - buf.append(resultSet.getStatementProxy().getConnectionProxy().getId()); - buf.append(", "); - buf.append(stmtId(resultSet)); - buf.append(", rs-"); - buf.append(resultSet.getId()); - buf.append("}"); - buf.append(" Result: ["); - - ResultSetMetaData meta = resultSet.getMetaData(); - for (int i = 0, size = meta.getColumnCount(); i < size; ++i) { - if (i != 0) { - buf.append(", "); - } - int columnIndex = i + 1; - int type = meta.getColumnType(columnIndex); - - Object value; - if (type == Types.TIMESTAMP) { - value = resultSet.getTimestamp(columnIndex); - } else if (type == Types.BLOB) { - value = ""; - } else if (type == Types.CLOB) { - value = ""; - } else if (type == Types.NCLOB) { - value = ""; - } else if (type == Types.BINARY) { - value = ""; - } else { - value = resultSet.getObject(columnIndex); - } - buf.append(value); - } - - buf.append("]"); - - resultSetLog(buf.toString()); - } catch (SQLException ex) { - resultSetLogError("logging error", ex); - } - } - } - - return moreRows; - } - - @Override - public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, int parameterIndex) - throws SQLException { - Object obj = chain.callableStatement_getObject(statement, parameterIndex); - - if (obj instanceof ResultSetProxy) { - resultSetOpenAfter((ResultSetProxy) obj); - } - - return obj; - } - - @Override - public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, int parameterIndex, - java.util.Map> map) throws SQLException { - Object obj = chain.callableStatement_getObject(statement, parameterIndex, map); - - if (obj instanceof ResultSetProxy) { - resultSetOpenAfter((ResultSetProxy) obj); - } - - return obj; - } - - @Override - public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, String parameterName) - throws SQLException { - Object obj = chain.callableStatement_getObject(statement, parameterName); - - if (obj instanceof ResultSetProxy) { - resultSetOpenAfter((ResultSetProxy) obj); - } - - return obj; - } - - @Override - public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, - String parameterName, java.util.Map> map) - throws SQLException { - Object obj = chain.callableStatement_getObject(statement, parameterName, map); - - if (obj instanceof ResultSetProxy) { - resultSetOpenAfter((ResultSetProxy) obj); - } - - return obj; - } - - @Override - protected void resultSetOpenAfter(ResultSetProxy resultSet) { - if (resultSetOpenAfterLogEnable && isResultSetLogEnabled()) { - try { - StringBuffer buf = new StringBuffer(); - buf.append("{conn-"); - buf.append(resultSet.getStatementProxy().getConnectionProxy().getId()); - buf.append(", "); - buf.append(stmtId(resultSet)); - buf.append(", rs-"); - buf.append(resultSet.getId()); - buf.append("}"); - - String resultId = buf.toString(); - resultSetLog(resultId + " open"); - - buf.append(" Header: ["); - - ResultSetMetaData meta = resultSet.getMetaData(); - for (int i = 0, size = meta.getColumnCount(); i < size; ++i) { - if (i != 0) { - buf.append(", "); - } - buf.append(meta.getColumnName(i + 1)); - } - buf.append("]"); - - resultSetLog(buf.toString()); - } catch (SQLException ex) { - resultSetLogError("logging error", ex); - } - } - } - - protected void statementCreateAfter(StatementProxy statement) { - if (statementCreateAfterLogEnable && isStatementLogEnabled()) { - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", stmt-" + statement.getId() - + "} created"); - } - } - - protected void statementPrepareAfter(PreparedStatementProxy statement) { - if (statementPrepareAfterLogEnable && isStatementLogEnabled()) { - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", pstmt-" + statement.getId() - + "} created. " + statement.getSql()); - } - } - - protected void statementPrepareCallAfter(CallableStatementProxy statement) { - if (statementPrepareCallAfterLogEnable && isStatementLogEnabled()) { - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", cstmt-" + statement.getId() - + "} created. " + statement.getSql()); - } - } - - @Override - protected void statement_executeErrorAfter(StatementProxy statement, String sql, Throwable error) { - if (this.isStatementLogErrorEnabled()) { - statementLogError("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) - + "} execute error. " + sql, error); - } - } - - private String stmtId(ResultSetProxy resultSet) { - return stmtId(resultSet.getStatementProxy()); - } - - private String stmtId(StatementProxy statement) { - StringBuffer buf = new StringBuffer(); - if (statement instanceof CallableStatementProxy) { - buf.append("cstmt-"); - } else if (statement instanceof PreparedStatementProxy) { - buf.append("pstmt-"); - } else { - buf.append("stmt-"); - } - buf.append(statement.getId()); - - return buf.toString(); - } - - protected void logParameter(PreparedStatementProxy statement) { - if (statementParameterSetLogEnable && isStatementLogEnabled()) { - { - StringBuffer buf = new StringBuffer(); - buf.append("{conn-"); - buf.append(statement.getConnectionProxy().getId()); - buf.append(", "); - buf.append(stmtId(statement)); - buf.append("}"); - buf.append(" Parameters : ["); - int parameterIndex = 0; - for (JdbcParameter parameter : statement.getParameters().values()) { - if (parameterIndex != 0) { - buf.append(", "); - } - int sqlType = parameter.getSqlType(); - Object value = parameter.getValue(); - switch (sqlType) { - case Types.NULL: - buf.append("NULL"); - break; - default: - buf.append(String.valueOf(value)); - break; - } - parameterIndex++; - } - buf.append("]"); - statementLog(buf.toString()); - } - { - StringBuffer buf = new StringBuffer(); - buf.append("{conn-"); - buf.append(statement.getConnectionProxy().getId()); - buf.append(", "); - buf.append(stmtId(statement)); - buf.append("}"); - buf.append(" Types : ["); - int parameterIndex = 0; - for (JdbcParameter parameter : statement.getParameters().values()) { - if (parameterIndex != 0) { - buf.append(", "); - } - int sqlType = parameter.getSqlType(); - buf.append(JdbcUtils.getTypeName(sqlType)); - parameterIndex++; - } - buf.append("]"); - statementLog(buf.toString()); - } - } - } - - @Override - public void dataSource_releaseConnection(FilterChain chain, DruidPooledConnection conn) throws SQLException { - long connectionId = -1; - - if (conn.getConnectionHolder() != null) { - ConnectionProxy connection = (ConnectionProxy) conn.getConnectionHolder().getConnection(); - connectionId = connection.getId(); - } - - chain.dataSource_recycle(conn); - - if (connectionCloseAfterLogEnable && isConnectionLogEnabled()) { - connectionLog("{conn-" + connectionId + "} pool-recycle"); - } - } - - @Override - public DruidPooledConnection dataSource_getConnection(FilterChain chain, DruidDataSource dataSource, - long maxWaitMillis) throws SQLException { - DruidPooledConnection conn = chain.dataSource_connect(dataSource, maxWaitMillis); - - ConnectionProxy connection = (ConnectionProxy) conn.getConnectionHolder().getConnection(); - - if (connectionConnectAfterLogEnable && isConnectionLogEnabled()) { - connectionLog("{conn-" + connection.getId() + "} pool-connect"); - } - - return conn; - } - - @Override - public void preparedStatement_clearParameters(FilterChain chain, PreparedStatementProxy statement) - throws SQLException { - - statementLog("{conn-" + statement.getConnectionProxy().getId() + ", pstmt-" + statement.getId() - + "} clearParameters. "); - - chain.preparedStatement_clearParameters(statement); - } - - @Override - public boolean isWrapperFor(Class iface) { - return iface == this.getClass() || iface == LogFilter.class; - } - - @SuppressWarnings("unchecked") - @Override - public T unwrap(Class iface) { - if (iface == this.getClass() || iface == LogFilter.class) { - return (T) this; - } - return null; - } -} +/* + * Copyright 1999-2011 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.filter.logging; + +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Savepoint; +import java.sql.Types; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.alibaba.druid.filter.FilterChain; +import com.alibaba.druid.filter.FilterEventAdapter; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledConnection; +import com.alibaba.druid.proxy.jdbc.CallableStatementProxy; +import com.alibaba.druid.proxy.jdbc.ConnectionProxy; +import com.alibaba.druid.proxy.jdbc.DataSourceProxy; +import com.alibaba.druid.proxy.jdbc.JdbcParameter; +import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy; +import com.alibaba.druid.proxy.jdbc.ResultSetProxy; +import com.alibaba.druid.proxy.jdbc.StatementProxy; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.util.JdbcUtils; + +/** + * @author wenshao + */ +public abstract class LogFilter extends FilterEventAdapter implements LogFilterMBean { + + protected String dataSourceLoggerName = "druid.sql.DataSource"; + protected String connectionLoggerName = "druid.sql.Connection"; + protected String statementLoggerName = "druid.sql.Statement"; + protected String resultSetLoggerName = "druid.sql.ResultSet"; + + private boolean connectionConnectBeforeLogEnable = true; + private boolean connectionConnectAfterLogEnable = true; + private boolean connectionCommitAfterLogEnable = true; + private boolean connectionRollbackAfterLogEnable = true; + private boolean connectionCloseAfterLogEnable = true; + + private boolean statementCreateAfterLogEnable = true; + private boolean statementPrepareAfterLogEnable = true; + private boolean statementPrepareCallAfterLogEnable = true; + + private boolean statementExecuteAfterLogEnable = true; + private boolean statementExecuteQueryAfterLogEnable = true; + private boolean statementExecuteUpdateAfterLogEnable = true; + private boolean statementExecuteBatchAfterLogEnable = true; + private boolean statementExecutableSqlLogEnable = false; + + private boolean statementCloseAfterLogEnable = true; + + private boolean statementParameterClearLogEnable = true; + private boolean statementParameterSetLogEnable = true; + + private boolean resultSetNextAfterLogEnable = true; + private boolean resultSetOpenAfterLogEnable = true; + private boolean resultSetCloseAfterLogEnable = true; + + private boolean dataSourceLogEnabled = true; + private boolean connectionLogEnabled = true; + private boolean connectionLogErrorEnabled = true; + private boolean statementLogEnabled = true; + private boolean statementLogErrorEnabled = true; + private boolean resultSetLogEnabled = true; + private boolean resultSetLogErrorEnabled = true; + + protected DataSourceProxy dataSource; + + public LogFilter(){ + { + String prop = System.getProperty("druid.log.stmt"); + if (prop == "false") { + statementLogEnabled = false; + } + } + { + String prop = System.getProperty("druid.log.rs"); + if (prop == "false") { + resultSetLogEnabled = false; + } + } + { + String prop = System.getProperty("druid.log.stmt.executableSql"); + if (prop == "true") { + statementExecutableSqlLogEnable = true; + } + } + } + + @Override + public void init(DataSourceProxy dataSource) { + this.dataSource = dataSource; + } + + public boolean isConnectionLogErrorEnabled() { + return connectionLogErrorEnabled; + } + + public boolean isResultSetCloseAfterLogEnabled() { + return isResultSetLogEnabled() && resultSetCloseAfterLogEnable; + } + + public void setResultSetCloseAfterLogEnabled(boolean resultSetCloseAfterLogEnable) { + this.resultSetCloseAfterLogEnable = resultSetCloseAfterLogEnable; + } + + public void setConnectionLogErrorEnabled(boolean connectionLogErrorEnabled) { + this.connectionLogErrorEnabled = connectionLogErrorEnabled; + } + + public boolean isResultSetLogErrorEnabled() { + return resultSetLogErrorEnabled; + } + + public void setResultSetLogErrorEnabled(boolean resultSetLogErrorEnabled) { + this.resultSetLogErrorEnabled = resultSetLogErrorEnabled; + } + + public boolean isConnectionConnectBeforeLogEnabled() { + return isConnectionLogEnabled() && connectionConnectBeforeLogEnable; + } + + public void setConnectionConnectBeforeLogEnabled(boolean beforeConnectionConnectLogEnable) { + this.connectionConnectBeforeLogEnable = beforeConnectionConnectLogEnable; + } + + public boolean isConnectionCloseAfterLogEnabled() { + return isConnectionLogEnabled() && connectionCloseAfterLogEnable; + } + + public boolean isConnectionRollbackAfterLogEnabled() { + return isConnectionLogEnabled() && connectionRollbackAfterLogEnable; + } + + public void setConnectionRollbackAfterLogEnabled(boolean connectionRollbackAfterLogEnable) { + this.connectionRollbackAfterLogEnable = connectionRollbackAfterLogEnable; + } + + public void setConnectionCloseAfterLogEnabled(boolean afterConnectionCloseLogEnable) { + this.connectionCloseAfterLogEnable = afterConnectionCloseLogEnable; + } + + public boolean isConnectionCommitAfterLogEnabled() { + return isConnectionLogEnabled() && connectionCommitAfterLogEnable; + } + + public void setConnectionCommitAfterLogEnabled(boolean afterConnectionCommitLogEnable) { + this.connectionCommitAfterLogEnable = afterConnectionCommitLogEnable; + } + + public boolean isConnectionConnectAfterLogEnabled() { + return isConnectionLogEnabled() && connectionConnectAfterLogEnable; + } + + public void setConnectionConnectAfterLogEnabled(boolean afterConnectionConnectLogEnable) { + this.connectionConnectAfterLogEnable = afterConnectionConnectLogEnable; + } + + public boolean isResultSetNextAfterLogEnabled() { + return isResultSetLogEnabled() && resultSetNextAfterLogEnable; + } + + public void setResultSetNextAfterLogEnabled(boolean afterResultSetNextLogEnable) { + this.resultSetNextAfterLogEnable = afterResultSetNextLogEnable; + } + + public boolean isResultSetOpenAfterLogEnabled() { + return isResultSetLogEnabled() && resultSetOpenAfterLogEnable; + } + + public void setResultSetOpenAfterLogEnabled(boolean afterResultSetOpenLogEnable) { + this.resultSetOpenAfterLogEnable = afterResultSetOpenLogEnable; + } + + public boolean isStatementCloseAfterLogEnabled() { + return isStatementLogEnabled() && statementCloseAfterLogEnable; + } + + public void setStatementCloseAfterLogEnabled(boolean afterStatementCloseLogEnable) { + this.statementCloseAfterLogEnable = afterStatementCloseLogEnable; + } + + public boolean isStatementCreateAfterLogEnabled() { + return isStatementLogEnabled() && statementCreateAfterLogEnable; + } + + public void setStatementCreateAfterLogEnabled(boolean afterStatementCreateLogEnable) { + this.statementCreateAfterLogEnable = afterStatementCreateLogEnable; + } + + public boolean isStatementExecuteBatchAfterLogEnabled() { + return isStatementLogEnabled() && statementExecuteBatchAfterLogEnable; + } + + public void setStatementExecuteBatchAfterLogEnabled(boolean afterStatementExecuteBatchLogEnable) { + this.statementExecuteBatchAfterLogEnable = afterStatementExecuteBatchLogEnable; + } + + public boolean isStatementExecuteAfterLogEnabled() { + return isStatementLogEnabled() && statementExecuteAfterLogEnable; + } + + public void setStatementExecuteAfterLogEnabled(boolean afterStatementExecuteLogEnable) { + this.statementExecuteAfterLogEnable = afterStatementExecuteLogEnable; + } + + public boolean isStatementExecuteQueryAfterLogEnabled() { + return isStatementLogEnabled() && statementExecuteQueryAfterLogEnable; + } + + public void setStatementExecuteQueryAfterLogEnabled(boolean afterStatementExecuteQueryLogEnable) { + this.statementExecuteQueryAfterLogEnable = afterStatementExecuteQueryLogEnable; + } + + public boolean isStatementExecuteUpdateAfterLogEnabled() { + return isStatementLogEnabled() && statementExecuteUpdateAfterLogEnable; + } + + public void setStatementExecuteUpdateAfterLogEnabled(boolean afterStatementExecuteUpdateLogEnable) { + this.statementExecuteUpdateAfterLogEnable = afterStatementExecuteUpdateLogEnable; + } + + public boolean isStatementExecutableSqlLogEnable() { + return statementExecutableSqlLogEnable; + } + + public void setStatementExecutableSqlLogEnable(boolean statementExecutableSqlLogEnable) { + this.statementExecutableSqlLogEnable = statementExecutableSqlLogEnable; + } + + public boolean isStatementPrepareCallAfterLogEnabled() { + return isStatementLogEnabled() && statementPrepareCallAfterLogEnable; + } + + public void setStatementPrepareCallAfterLogEnabled(boolean afterStatementPrepareCallLogEnable) { + this.statementPrepareCallAfterLogEnable = afterStatementPrepareCallLogEnable; + } + + public boolean isStatementPrepareAfterLogEnabled() { + return isStatementLogEnabled() && statementPrepareAfterLogEnable; + } + + public void setStatementPrepareAfterLogEnabled(boolean afterStatementPrepareLogEnable) { + this.statementPrepareAfterLogEnable = afterStatementPrepareLogEnable; + } + + public boolean isDataSourceLogEnabled() { + return dataSourceLogEnabled; + } + + public void setDataSourceLogEnabled(boolean dataSourceLogEnabled) { + this.dataSourceLogEnabled = dataSourceLogEnabled; + } + + public boolean isConnectionLogEnabled() { + return connectionLogEnabled; + } + + public void setConnectionLogEnabled(boolean connectionLogEnabled) { + this.connectionLogEnabled = connectionLogEnabled; + } + + public boolean isStatementLogEnabled() { + return statementLogEnabled; + } + + public void setStatementLogEnabled(boolean statementLogEnabled) { + this.statementLogEnabled = statementLogEnabled; + } + + public boolean isStatementLogErrorEnabled() { + return statementLogErrorEnabled; + } + + public void setStatementLogErrorEnabled(boolean statementLogErrorEnabled) { + this.statementLogErrorEnabled = statementLogErrorEnabled; + } + + public boolean isResultSetLogEnabled() { + return resultSetLogEnabled; + } + + public void setResultSetLogEnabled(boolean resultSetLogEnabled) { + this.resultSetLogEnabled = resultSetLogEnabled; + } + + public boolean isStatementParameterSetLogEnabled() { + return isStatementLogEnabled() && statementParameterSetLogEnable; + } + + public void setStatementParameterSetLogEnabled(boolean statementParameterSetLogEnable) { + this.statementParameterSetLogEnable = statementParameterSetLogEnable; + } + + public boolean isStatementParameterClearLogEnable() { + return isStatementLogEnabled() && statementParameterClearLogEnable; + } + + public void setStatementParameterClearLogEnable(boolean statementParameterClearLogEnable) { + this.statementParameterClearLogEnable = statementParameterClearLogEnable; + } + + protected abstract void connectionLog(String message); + + protected abstract void statementLog(String message); + + protected abstract void statementLogError(String message, Throwable error); + + protected abstract void resultSetLog(String message); + + protected abstract void resultSetLogError(String message, Throwable error); + + public void connection_connectAfter(ConnectionProxy connection) { + if (connectionConnectAfterLogEnable && isConnectionLogEnabled()) { + connectionLog("{conn-" + connection.getId() + "} connected"); + } + } + + @Override + public Savepoint connection_setSavepoint(FilterChain chain, ConnectionProxy connection) throws SQLException { + + Savepoint savepoint = chain.connection_setSavepoint(connection); + + if (isConnectionLogEnabled()) { + connectionLog("{conn " + connection.getId() + "} setSavepoint-" + savepoint.getSavepointId()); + } + + return savepoint; + } + + @Override + public Savepoint connection_setSavepoint(FilterChain chain, ConnectionProxy connection, String name) + throws SQLException { + Savepoint savepoint = chain.connection_setSavepoint(connection, name); + + if (isConnectionLogEnabled()) { + connectionLog("{conn " + connection.getId() + "} setSavepoint-" + name); + } + + return savepoint; + } + + @Override + public void connection_rollback(FilterChain chain, ConnectionProxy connection) throws SQLException { + super.connection_rollback(chain, connection); + + if (connectionRollbackAfterLogEnable && isConnectionLogEnabled()) { + connectionLog("{conn " + connection.getId() + "} rollback"); + } + } + + @Override + public void connection_rollback(FilterChain chain, ConnectionProxy connection, Savepoint savePoint) + throws SQLException { + super.connection_rollback(chain, connection, savePoint); + + if (connectionRollbackAfterLogEnable && isConnectionLogEnabled()) { + connectionLog("{conn " + connection.getId() + "} rollback -> " + savePoint.getSavepointId()); + } + } + + @Override + public void connection_commit(FilterChain chain, ConnectionProxy connection) throws SQLException { + super.connection_commit(chain, connection); + + if (connectionCommitAfterLogEnable && isConnectionLogEnabled()) { + connectionLog("{conn-" + connection.getId() + "} commited"); + } + } + + @Override + public void connection_setAutoCommit(FilterChain chain, ConnectionProxy connection, boolean autoCommit) + throws SQLException { + + connectionLog("{conn-" + connection.getId() + "} setAutoCommit " + autoCommit); + chain.connection_setAutoCommit(connection, autoCommit); + } + + @Override + public void connection_close(FilterChain chain, ConnectionProxy connection) throws SQLException { + super.connection_close(chain, connection); + + if (connectionCloseAfterLogEnable && isConnectionLogEnabled()) { + connectionLog("{conn-" + connection.getId() + "} closed"); + } + } + + @Override + public void statement_close(FilterChain chain, StatementProxy statement) throws SQLException { + super.statement_close(chain, statement); + + if (statementCloseAfterLogEnable && isStatementLogEnabled()) { + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} closed"); + } + } + + @Override + protected void statementExecuteBefore(StatementProxy statement, String sql) { + statement.setLastExecuteStartNano(); + if (statement instanceof PreparedStatementProxy) { + logParameter((PreparedStatementProxy) statement); + } + } + + @Override + protected void statementExecuteAfter(StatementProxy statement, String sql, boolean firstResult) { + logExecutableSql(statement, sql); + + if (statementExecuteAfterLogEnable && isStatementLogEnabled()) { + statement.setLastExecuteTimeNano(); + double nanos = statement.getLastExecuteTimeNano(); + double millis = nanos / (1000 * 1000); + + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. " + + millis + " millis. " + sql); + } + } + + @Override + protected void statementExecuteBatchBefore(StatementProxy statement) { + statement.setLastExecuteStartNano(); + } + + @Override + protected void statementExecuteBatchAfter(StatementProxy statement, int[] result) { + String sql; + if (statement instanceof PreparedStatementProxy) { + sql = ((PreparedStatementProxy) statement).getSql(); + } else { + sql = statement.getBatchSql(); + } + + logExecutableSql(statement, sql); + + if (statementExecuteBatchAfterLogEnable && isStatementLogEnabled()) { + statement.setLastExecuteTimeNano(); + double nanos = statement.getLastExecuteTimeNano(); + double millis = nanos / (1000 * 1000); + + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + + "} batch executed. " + millis + " millis. " + sql); + } + } + + @Override + protected void statementExecuteQueryBefore(StatementProxy statement, String sql) { + statement.setLastExecuteStartNano(); + if (statement instanceof PreparedStatementProxy) { + logParameter((PreparedStatementProxy) statement); + } + } + + @Override + protected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) { + logExecutableSql(statement, sql); + + if (statementExecuteQueryAfterLogEnable && isStatementLogEnabled()) { + statement.setLastExecuteTimeNano(); + double nanos = statement.getLastExecuteTimeNano(); + double millis = nanos / (1000 * 1000); + + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + ", rs-" + + resultSet.getId() + "} query executed. " + millis + " millis. " + sql); + } + } + + @Override + protected void statementExecuteUpdateBefore(StatementProxy statement, String sql) { + statement.setLastExecuteStartNano(); + if (statement instanceof PreparedStatementProxy) { + logParameter((PreparedStatementProxy) statement); + } + } + + @Override + protected void statementExecuteUpdateAfter(StatementProxy statement, String sql, int updateCount) { + logExecutableSql(statement, sql); + + if (statementExecuteUpdateAfterLogEnable && isStatementLogEnabled()) { + statement.setLastExecuteTimeNano(); + double nanos = statement.getLastExecuteTimeNano(); + double millis = nanos / (1000 * 1000); + + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + + "} update executed. effort " + updateCount + ". " + millis + " millis. " + sql); + } + } + + private void logExecutableSql(StatementProxy statement, String sql) { + if (!isStatementExecutableSqlLogEnable()) { + return; + } + + Map parameterMap = statement.getParameters(); + if (parameterMap == null || parameterMap.size() == 0) { + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. " + + sql); + return; + } + + List parameters = new ArrayList(parameterMap.size()); + for (JdbcParameter jdbcParam : parameterMap.values()) { + parameters.add(jdbcParam.getValue()); + } + + String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType(); + String formattedSql = SQLUtils.format(sql, dbType, parameters); + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. " + + formattedSql); + } + + @Override + public void resultSet_close(FilterChain chain, ResultSetProxy resultSet) throws SQLException { + chain.resultSet_close(resultSet); + + StringBuffer buf = new StringBuffer(); + buf.append("{conn-"); + buf.append(resultSet.getStatementProxy().getConnectionProxy().getId()); + buf.append(", "); + buf.append(stmtId(resultSet)); + buf.append(", rs-"); + buf.append(resultSet.getId()); + buf.append("} closed"); + + if (isResultSetCloseAfterLogEnabled()) { + resultSetLog(buf.toString()); + } + } + + @Override + public boolean resultSet_next(FilterChain chain, ResultSetProxy resultSet) throws SQLException { + boolean moreRows = super.resultSet_next(chain, resultSet); + + if (moreRows) { + if (resultSetNextAfterLogEnable && isResultSetLogEnabled()) { + try { + StringBuffer buf = new StringBuffer(); + buf.append("{conn-"); + buf.append(resultSet.getStatementProxy().getConnectionProxy().getId()); + buf.append(", "); + buf.append(stmtId(resultSet)); + buf.append(", rs-"); + buf.append(resultSet.getId()); + buf.append("}"); + buf.append(" Result: ["); + + ResultSetMetaData meta = resultSet.getMetaData(); + for (int i = 0, size = meta.getColumnCount(); i < size; ++i) { + if (i != 0) { + buf.append(", "); + } + int columnIndex = i + 1; + int type = meta.getColumnType(columnIndex); + + Object value; + if (type == Types.TIMESTAMP) { + value = resultSet.getTimestamp(columnIndex); + } else if (type == Types.BLOB) { + value = ""; + } else if (type == Types.CLOB) { + value = ""; + } else if (type == Types.NCLOB) { + value = ""; + } else if (type == Types.BINARY) { + value = ""; + } else { + value = resultSet.getObject(columnIndex); + } + buf.append(value); + } + + buf.append("]"); + + resultSetLog(buf.toString()); + } catch (SQLException ex) { + resultSetLogError("logging error", ex); + } + } + } + + return moreRows; + } + + @Override + public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, int parameterIndex) + throws SQLException { + Object obj = chain.callableStatement_getObject(statement, parameterIndex); + + if (obj instanceof ResultSetProxy) { + resultSetOpenAfter((ResultSetProxy) obj); + } + + return obj; + } + + @Override + public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, int parameterIndex, + java.util.Map> map) throws SQLException { + Object obj = chain.callableStatement_getObject(statement, parameterIndex, map); + + if (obj instanceof ResultSetProxy) { + resultSetOpenAfter((ResultSetProxy) obj); + } + + return obj; + } + + @Override + public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, String parameterName) + throws SQLException { + Object obj = chain.callableStatement_getObject(statement, parameterName); + + if (obj instanceof ResultSetProxy) { + resultSetOpenAfter((ResultSetProxy) obj); + } + + return obj; + } + + @Override + public Object callableStatement_getObject(FilterChain chain, CallableStatementProxy statement, + String parameterName, java.util.Map> map) + throws SQLException { + Object obj = chain.callableStatement_getObject(statement, parameterName, map); + + if (obj instanceof ResultSetProxy) { + resultSetOpenAfter((ResultSetProxy) obj); + } + + return obj; + } + + @Override + protected void resultSetOpenAfter(ResultSetProxy resultSet) { + if (resultSetOpenAfterLogEnable && isResultSetLogEnabled()) { + try { + StringBuffer buf = new StringBuffer(); + buf.append("{conn-"); + buf.append(resultSet.getStatementProxy().getConnectionProxy().getId()); + buf.append(", "); + buf.append(stmtId(resultSet)); + buf.append(", rs-"); + buf.append(resultSet.getId()); + buf.append("}"); + + String resultId = buf.toString(); + resultSetLog(resultId + " open"); + + buf.append(" Header: ["); + + ResultSetMetaData meta = resultSet.getMetaData(); + for (int i = 0, size = meta.getColumnCount(); i < size; ++i) { + if (i != 0) { + buf.append(", "); + } + buf.append(meta.getColumnName(i + 1)); + } + buf.append("]"); + + resultSetLog(buf.toString()); + } catch (SQLException ex) { + resultSetLogError("logging error", ex); + } + } + } + + protected void statementCreateAfter(StatementProxy statement) { + if (statementCreateAfterLogEnable && isStatementLogEnabled()) { + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", stmt-" + statement.getId() + + "} created"); + } + } + + protected void statementPrepareAfter(PreparedStatementProxy statement) { + if (statementPrepareAfterLogEnable && isStatementLogEnabled()) { + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", pstmt-" + statement.getId() + + "} created. " + statement.getSql()); + } + } + + protected void statementPrepareCallAfter(CallableStatementProxy statement) { + if (statementPrepareCallAfterLogEnable && isStatementLogEnabled()) { + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", cstmt-" + statement.getId() + + "} created. " + statement.getSql()); + } + } + + @Override + protected void statement_executeErrorAfter(StatementProxy statement, String sql, Throwable error) { + if (this.isStatementLogErrorEnabled()) { + statementLogError("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + + "} execute error. " + sql, error); + } + } + + private String stmtId(ResultSetProxy resultSet) { + return stmtId(resultSet.getStatementProxy()); + } + + private String stmtId(StatementProxy statement) { + StringBuffer buf = new StringBuffer(); + if (statement instanceof CallableStatementProxy) { + buf.append("cstmt-"); + } else if (statement instanceof PreparedStatementProxy) { + buf.append("pstmt-"); + } else { + buf.append("stmt-"); + } + buf.append(statement.getId()); + + return buf.toString(); + } + + protected void logParameter(PreparedStatementProxy statement) { + if (isStatementParameterSetLogEnabled()) { + { + StringBuffer buf = new StringBuffer(); + buf.append("{conn-"); + buf.append(statement.getConnectionProxy().getId()); + buf.append(", "); + buf.append(stmtId(statement)); + buf.append("}"); + buf.append(" Parameters : ["); + int parameterIndex = 0; + for (JdbcParameter parameter : statement.getParameters().values()) { + if (parameterIndex != 0) { + buf.append(", "); + } + int sqlType = parameter.getSqlType(); + Object value = parameter.getValue(); + switch (sqlType) { + case Types.NULL: + buf.append("NULL"); + break; + default: + buf.append(String.valueOf(value)); + break; + } + parameterIndex++; + } + buf.append("]"); + statementLog(buf.toString()); + } + { + StringBuffer buf = new StringBuffer(); + buf.append("{conn-"); + buf.append(statement.getConnectionProxy().getId()); + buf.append(", "); + buf.append(stmtId(statement)); + buf.append("}"); + buf.append(" Types : ["); + int parameterIndex = 0; + for (JdbcParameter parameter : statement.getParameters().values()) { + if (parameterIndex != 0) { + buf.append(", "); + } + int sqlType = parameter.getSqlType(); + buf.append(JdbcUtils.getTypeName(sqlType)); + parameterIndex++; + } + buf.append("]"); + statementLog(buf.toString()); + } + } + } + + @Override + public void dataSource_releaseConnection(FilterChain chain, DruidPooledConnection conn) throws SQLException { + long connectionId = -1; + + if (conn.getConnectionHolder() != null) { + ConnectionProxy connection = (ConnectionProxy) conn.getConnectionHolder().getConnection(); + connectionId = connection.getId(); + } + + chain.dataSource_recycle(conn); + + if (connectionCloseAfterLogEnable && isConnectionLogEnabled()) { + connectionLog("{conn-" + connectionId + "} pool-recycle"); + } + } + + @Override + public DruidPooledConnection dataSource_getConnection(FilterChain chain, DruidDataSource dataSource, + long maxWaitMillis) throws SQLException { + DruidPooledConnection conn = chain.dataSource_connect(dataSource, maxWaitMillis); + + ConnectionProxy connection = (ConnectionProxy) conn.getConnectionHolder().getConnection(); + + if (connectionConnectAfterLogEnable && isConnectionLogEnabled()) { + connectionLog("{conn-" + connection.getId() + "} pool-connect"); + } + + return conn; + } + + @Override + public void preparedStatement_clearParameters(FilterChain chain, PreparedStatementProxy statement) + throws SQLException { + + if (isStatementParameterClearLogEnable()) { + statementLog("{conn-" + statement.getConnectionProxy().getId() + ", pstmt-" + statement.getId() + + "} clearParameters. "); + } + chain.preparedStatement_clearParameters(statement); + } + + @Override + public boolean isWrapperFor(Class iface) { + return iface == this.getClass() || iface == LogFilter.class; + } + + @SuppressWarnings("unchecked") + @Override + public T unwrap(Class iface) { + if (iface == this.getClass() || iface == LogFilter.class) { + return (T) this; + } + return null; + } +} diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index f750d03d15..9642bbd78f 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -1,2271 +1,2281 @@ -/* - * Copyright 1999-2011 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.io.Closeable; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.ConcurrentModificationException; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.ServiceLoader; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import javax.management.JMException; -import javax.management.ObjectName; -import javax.naming.NamingException; -import javax.naming.Reference; -import javax.naming.Referenceable; -import javax.naming.StringRefAddr; -import javax.sql.ConnectionEvent; -import javax.sql.ConnectionEventListener; -import javax.sql.ConnectionPoolDataSource; -import javax.sql.PooledConnection; - -import com.alibaba.druid.Constants; -import com.alibaba.druid.TransactionTimeoutException; -import com.alibaba.druid.VERSION; -import com.alibaba.druid.filter.AutoLoad; -import com.alibaba.druid.filter.Filter; -import com.alibaba.druid.filter.FilterChainImpl; -import com.alibaba.druid.mock.MockDriver; -import com.alibaba.druid.pool.DruidPooledPreparedStatement.PreparedStatementKey; -import com.alibaba.druid.pool.vendor.InformixExceptionSorter; -import com.alibaba.druid.pool.vendor.MSSQLValidConnectionChecker; -import com.alibaba.druid.pool.vendor.MockExceptionSorter; -import com.alibaba.druid.pool.vendor.MySqlExceptionSorter; -import com.alibaba.druid.pool.vendor.MySqlValidConnectionChecker; -import com.alibaba.druid.pool.vendor.OracleExceptionSorter; -import com.alibaba.druid.pool.vendor.OracleValidConnectionChecker; -import com.alibaba.druid.pool.vendor.SybaseExceptionSorter; -import com.alibaba.druid.proxy.DruidDriver; -import com.alibaba.druid.proxy.jdbc.DataSourceProxyConfig; -import com.alibaba.druid.proxy.jdbc.TransactionInfo; -import com.alibaba.druid.sql.ast.SQLStatement; -import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; -import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; -import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; -import com.alibaba.druid.sql.parser.SQLParserUtils; -import com.alibaba.druid.sql.parser.SQLStatementParser; -import com.alibaba.druid.stat.DruidDataSourceStatManager; -import com.alibaba.druid.stat.JdbcDataSourceStat; -import com.alibaba.druid.stat.JdbcSqlStat; -import com.alibaba.druid.support.logging.Log; -import com.alibaba.druid.support.logging.LogFactory; -import com.alibaba.druid.util.IOUtils; -import com.alibaba.druid.util.JMXUtils; -import com.alibaba.druid.util.JdbcConstants; -import com.alibaba.druid.util.JdbcUtils; -import com.alibaba.druid.util.StringUtils; -import com.alibaba.druid.wall.WallFilter; - -; -/** - * @author ljw - * @author wenshao - */ -public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource { - - private final static Log LOG = LogFactory.getLog(DruidDataSource.class); - - private static final long serialVersionUID = 1L; - - // stats - private final AtomicLong recycleErrorCount = new AtomicLong(); - private long connectCount = 0L; - private long closeCount = 0L; - private final AtomicLong connectErrorCount = new AtomicLong(); - private long recycleCount = 0L; - private long removeAbandonedCount = 0L; - private long notEmptyWaitCount = 0L; - private long notEmptySignalCount = 0L; - private long notEmptyWaitNanos = 0L; - - private int activePeak = 0; - private long activePeakTime = 0; - private int poolingPeak = 0; - private long poolingPeakTime = 0; - - // store - private volatile DruidConnectionHolder[] connections; - private int poolingCount = 0; - private int activeCount = 0; - private long discardCount = 0; - private int notEmptyWaitThreadCount = 0; - private int notEmptyWaitThreadPeak = 0; - - // threads - private CreateConnectionThread createConnectionThread; - private DestroyConnectionThread destoryConnectionThread; - private LogStatsThread logStatsThread; - - private final CountDownLatch initedLatch = new CountDownLatch(2); - - private volatile boolean enable = true; - - private boolean resetStatEnable = true; - - private String initStackTrace; - - private volatile boolean closed = false; - private long closeTimeMillis = -1L; - - protected JdbcDataSourceStat dataSourceStat; - - private boolean useGloalDataSourceStat = false; - - public DruidDataSource(){ - this(false); - } - - public DruidDataSource(boolean fairLock){ - super(fairLock); - - configFromPropety(System.getProperties()); - } - - public void configFromPropety(Properties properties) { - { - String property = properties.getProperty("druid.testWhileIdle"); - if ("true".equals(property)) { - this.setTestWhileIdle(true); - } else if ("false".equals(property)) { - this.setTestWhileIdle(false); - } - } - { - String property = properties.getProperty("druid.testOnBorrow"); - if ("true".equals(property)) { - this.setTestOnBorrow(true); - } else if ("false".equals(property)) { - this.setTestOnBorrow(false); - } - } - { - String property = properties.getProperty("druid.validationQuery"); - if (property != null && property.length() > 0) { - this.setValidationQuery(property); - } - } - { - String property = properties.getProperty("druid.useGloalDataSourceStat"); - if ("true".equals(property)) { - this.setUseGloalDataSourceStat(true); - } else if ("false".equals(property)) { - this.setUseGloalDataSourceStat(false); - } - } - { - String property = properties.getProperty("druid.filters"); - - if (property != null && property.length() > 0) { - try { - this.setFilters(property); - } catch (SQLException e) { - LOG.error("setFilters error", e); - } - } - } - { - String property = properties.getProperty(Constants.DRUID_TIME_BETWEEN_LOG_STATS_MILLIS); - if (property != null && property.length() > 0) { - try { - long value = Long.parseLong(property); - this.setTimeBetweenLogStatsMillis(value); - } catch (NumberFormatException e) { - LOG.error("illegal property '" + Constants.DRUID_TIME_BETWEEN_LOG_STATS_MILLIS + "'", e); - } - } - } - { - String property = properties.getProperty(Constants.DRUID_STAT_SQL_MAX_SIZE); - if (property != null && property.length() > 0) { - try { - int value = Integer.parseInt(property); - if (dataSourceStat != null) { - dataSourceStat.setMaxSqlSize(value); - } - } catch (NumberFormatException e) { - LOG.error("illegal property '" + Constants.DRUID_STAT_SQL_MAX_SIZE + "'", e); - } - } - } - } - - public boolean isUseGloalDataSourceStat() { - return useGloalDataSourceStat; - } - - public void setUseGloalDataSourceStat(boolean useGloalDataSourceStat) { - this.useGloalDataSourceStat = useGloalDataSourceStat; - } - - public String getInitStackTrace() { - return initStackTrace; - } - - public boolean isResetStatEnable() { - return resetStatEnable; - } - - public void setResetStatEnable(boolean resetStatEnable) { - this.resetStatEnable = resetStatEnable; - } - - public long getDiscardCount() { - return discardCount; - } - - public void restart() { - lock.lock(); - try { - if (LOG.isInfoEnabled()) { - LOG.info("{dataSource-" + this.getID() + "} restart"); - } - - this.close(); - this.resetStat(); - this.inited = false; - this.enable = true; - this.closed = false; - } finally { - lock.unlock(); - } - } - - public void resetStat() { - if (!resetStatEnable) { - return; - } - - lock.lock(); - try { - connectCount = 0; - closeCount = 0; - discardCount = 0; - recycleCount = 0; - createCount.set(0); - destroyCount.set(0); - removeAbandonedCount = 0; - notEmptyWaitCount = 0; - notEmptySignalCount = 0L; - notEmptyWaitNanos = 0; - - activePeak = 0; - activePeakTime = 0; - poolingPeak = 0; - createTimespan = 0; - lastError = null; - lastErrorTimeMillis = 0; - lastCreateError = null; - lastCreateErrorTimeMillis = 0; - } finally { - lock.unlock(); - } - - connectErrorCount.set(0); - errorCount.set(0); - commitCount.set(0); - rollbackCount.set(0); - startTransactionCount.set(0); - cachedPreparedStatementHitCount.set(0); - closedPreparedStatementCount.set(0); - preparedStatementCount.set(0); - transactionHistogram.reset(); - cachedPreparedStatementDeleteCount.set(0); - recycleErrorCount.set(0); - } - - public boolean isEnable() { - return enable; - } - - public void setEnable(boolean enable) { - lock.lock(); - try { - this.enable = enable; - if (!enable) { - notEmpty.signalAll(); - notEmptySignalCount++; - } - } finally { - lock.unlock(); - } - } - - public void setPoolPreparedStatements(boolean value) { - if (this.poolPreparedStatements == value) { - return; - } - - this.poolPreparedStatements = value; - - if (!inited) { - return; - } - - if (LOG.isInfoEnabled()) { - LOG.info("set poolPreparedStatements " + this.poolPreparedStatements + " -> " + value); - } - - if (!value) { - lock.lock(); - try { - - for (int i = 0; i < poolingCount; ++i) { - DruidConnectionHolder connection = connections[i]; - - for (PreparedStatementHolder holder : connection.getStatementPool().getMap().values()) { - closePreapredStatement(holder); - } - - connection.getStatementPool().getMap().clear(); - } - } finally { - lock.unlock(); - } - } - } - - public void setMaxActive(int maxActive) { - if (this.maxActive == maxActive) { - return; - } - - if (maxActive == 0) { - throw new IllegalArgumentException("maxActive can't not set zero"); - } - - if (!inited) { - this.maxActive = maxActive; - return; - } - - if (maxActive < this.minIdle) { - throw new IllegalArgumentException("maxActive less than minIdle, " + maxActive + " < " + this.minIdle); - } - - if (LOG.isInfoEnabled()) { - LOG.info("maxActive changed : " + this.maxActive + " -> " + maxActive); - } - - lock.lock(); - try { - int allCount = this.poolingCount + this.activeCount; - - if (maxActive > allCount) { - this.connections = Arrays.copyOf(this.connections, maxActive); - } else { - this.connections = Arrays.copyOf(this.connections, allCount); - } - - this.maxActive = maxActive; - } finally { - lock.unlock(); - } - } - - @SuppressWarnings("rawtypes") - public void setConnectProperties(Properties properties) { - if (properties == null) { - properties = new Properties(); - } - - boolean equals; - if (properties.size() == this.connectProperties.size()) { - equals = true; - for (Map.Entry entry : properties.entrySet()) { - Object value = this.connectProperties.get(entry.getKey()); - Object entryValue = entry.getValue(); - if (value == null && entryValue != null) { - equals = false; - break; - } - - if (!value.equals(entry.getValue())) { - equals = false; - break; - } - } - } else { - equals = false; - } - - if (!equals) { - if (inited && LOG.isInfoEnabled()) { - LOG.info("connectProperties changed : " + this.connectProperties + " -> " + properties); - } - - configFromPropety(properties); - - for (Filter filter : this.filters) { - filter.configFromProperties(properties); - } - - if (exceptionSorter != null) { - exceptionSorter.configFromProperties(properties); - } - - if (validConnectionChecker != null) { - validConnectionChecker.configFromProperties(properties); - } - - if (statLogger != null) { - statLogger.configFromProperties(properties); - } - } - - this.connectProperties = properties; - } - - public boolean isInited() { - return this.inited; - } - - public void init() throws SQLException { - if (inited) { - return; - } - - final ReentrantLock lock = this.lock; - try { - lock.lockInterruptibly(); - } catch (InterruptedException e) { - throw new SQLException("interrupt", e); - } - - boolean init = false; - try { - if (inited) { - return; - } - - init = true; - - initStackTrace = IOUtils.toString(Thread.currentThread().getStackTrace()); - - this.id = DruidDriver.createDataSourceId(); - - if (this.dbType == null || this.dbType.length() == 0) { - this.dbType = JdbcUtils.getDbType(jdbcUrl, null); - } - - for (Filter filter : filters) { - filter.init(this); - } - - if (JdbcConstants.MYSQL.equals(this.dbType) || // - JdbcConstants.MARIADB.equals(this.dbType)) { - boolean cacheServerConfigurationSet = false; - if (this.connectProperties.containsKey("cacheServerConfiguration")) { - cacheServerConfigurationSet = true; - } else if (this.jdbcUrl.indexOf("cacheServerConfiguration") != -1) { - cacheServerConfigurationSet = true; - } - if (cacheServerConfigurationSet) { - this.connectProperties.put("cacheServerConfiguration", "true"); - } - } - - if (maxActive <= 0) { - throw new IllegalArgumentException("illegal maxActive " + maxActive); - } - - if (maxActive < minIdle) { - throw new IllegalArgumentException("illegal maxActive " + maxActive); - } - - if (getInitialSize() > maxActive) { - throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActieve " - + maxActive); - } - - if (timeBetweenLogStatsMillis > 0 && useGloalDataSourceStat) { - throw new IllegalArgumentException("timeBetweenLogStatsMillis not support useGloalDataSourceStat=true"); - } - - if (this.driverClass != null) { - this.driverClass = driverClass.trim(); - } - - validationQueryCheck(); - - if (this.jdbcUrl != null) { - this.jdbcUrl = this.jdbcUrl.trim(); - initFromWrapDriverUrl(); - } - - initFromSPIServiceLoader(); - - if (this.driver == null) { - if (this.driverClass == null || this.driverClass.isEmpty()) { - this.driverClass = JdbcUtils.getDriverClassName(this.jdbcUrl); - } - - if (MockDriver.class.getName().equals(driverClass)) { - driver = MockDriver.instance; - } else { - driver = JdbcUtils.createDriver(driverClassLoader, driverClass); - } - } else { - if (this.driverClass == null) { - this.driverClass = driver.getClass().getName(); - } - } - - if (this.dbType == null || this.dbType.length() == 0) { - this.dbType = JdbcUtils.getDbType(jdbcUrl, driverClass.getClass().getName()); - } - - initCheck(); - - initExceptionSorter(); - initValidConnectionChecker(); - - if (isUseGloalDataSourceStat()) { - dataSourceStat = JdbcDataSourceStat.getGlobal(); - if (dataSourceStat == null) { - dataSourceStat = new JdbcDataSourceStat("Global", "Global", this.dbType); - JdbcDataSourceStat.setGlobal(dataSourceStat); - } - if (dataSourceStat.getDbType() == null) { - dataSourceStat.setDbType(this.getDbType()); - } - } else { - dataSourceStat = new JdbcDataSourceStat(this.name, this.jdbcUrl, this.dbType, this.connectProperties); - } - - connections = new DruidConnectionHolder[maxActive]; - - SQLException connectError = null; - - try { - // init connections - for (int i = 0, size = getInitialSize(); i < size; ++i) { - Connection conn = createPhysicalConnection(); - DruidConnectionHolder holder = new DruidConnectionHolder(this, conn); - connections[poolingCount++] = holder; - } - - if (poolingCount > 0) { - poolingPeak = poolingCount; - poolingPeakTime = System.currentTimeMillis(); - } - } catch (SQLException ex) { - LOG.error("init datasource error", ex); - connectError = ex; - } - - createAndLogThread(); - createAndStartCreatorThread(); - createAndStartDestroyThread(); - - initedLatch.await(); - - initedTime = new Date(); - ObjectName objectName = DruidDataSourceStatManager.addDataSource(this, this.name); - this.setObjectName(objectName); - - if (connectError != null && poolingCount == 0) { - throw connectError; - } - } catch (SQLException e) { - LOG.error("dataSource init error", e); - throw e; - } catch (InterruptedException e) { - throw new SQLException(e.getMessage(), e); - } finally { - inited = true; - lock.unlock(); - - if (init && LOG.isInfoEnabled()) { - LOG.info("{dataSource-" + this.getID() + "} inited"); - } - } - } - - private void createAndLogThread() { - if (this.timeBetweenLogStatsMillis <= 0) { - return; - } - - String threadName = "Druid-ConnectionPool-Log-" + System.identityHashCode(this); - logStatsThread = new LogStatsThread(threadName); - logStatsThread.start(); - } - - private void createAndStartDestroyThread() { - String threadName = "Druid-ConnectionPool-Destory-" + System.identityHashCode(this); - destoryConnectionThread = new DestroyConnectionThread(threadName); - destoryConnectionThread.start(); - } - - protected void createAndStartCreatorThread() { - String threadName = "Druid-ConnectionPool-Create-" + System.identityHashCode(this); - createConnectionThread = new CreateConnectionThread(threadName); - createConnectionThread.start(); - } - - /** - * load filters from SPI ServiceLoader - * - * @see ServiceLoader - */ - private void initFromSPIServiceLoader() { - - String property = System.getProperty("druid.load.spifilter.skip"); - if (property != null) { - return; - } - - ServiceLoader druidAutoFilterLoader = ServiceLoader.load(Filter.class); - - for (Filter autoFilter : druidAutoFilterLoader) { - AutoLoad autoLoad = autoFilter.getClass().getAnnotation(AutoLoad.class); - if (autoLoad != null && autoLoad.value()) { - if (LOG.isInfoEnabled()) { - LOG.info("load filter from spi :" + autoFilter.getClass().getName()); - } - addFilter(autoFilter); - } - } - } - - private void initFromWrapDriverUrl() throws SQLException { - if (!jdbcUrl.startsWith(DruidDriver.DEFAULT_PREFIX)) { - return; - } - - DataSourceProxyConfig config = DruidDriver.parseConfig(jdbcUrl, null); - this.driverClass = config.getRawDriverClassName(); - - LOG.error("error url : '" + jdbcUrl + "', it should be : '" + config.getRawUrl() + "'"); - - this.jdbcUrl = config.getRawUrl(); - if (this.name == null) { - this.name = config.getName(); - } - - for (Filter filter : config.getFilters()) { - addFilter(filter); - } - } - - /** - * 会去重复 - * - * @param filter - */ - private void addFilter(Filter filter) { - boolean exists = false; - for (Filter initedFilter : this.filters) { - if (initedFilter.getClass() == filter.getClass()) { - exists = true; - break; - } - } - - if (!exists) { - filter.init(this); - this.filters.add(filter); - } - - } - - private void validationQueryCheck() { - if (!(isTestOnBorrow() || isTestOnReturn() || isTestWhileIdle())) { - return; - } - - if (this.validConnectionChecker != null) { - return; - } - - if (this.getValidationQuery() != null && this.getValidationQuery().length() > 0) { - return; - } - - String errorMessage = ""; - - if (isTestOnBorrow()) { - errorMessage += "testOnBorrow is true, "; - } - - if (isTestOnReturn()) { - errorMessage += "testOnReturn is true, "; - } - - if (isTestWhileIdle()) { - errorMessage += "testWhileIdle is true, "; - } - - LOG.error(errorMessage + "validationQuery not set"); - } - - protected void initCheck() throws SQLException { - if (JdbcUtils.ORACLE.equals(this.dbType)) { - isOracle = true; - - if (driver.getMajorVersion() < 10) { - throw new SQLException("not support oracle driver " + driver.getMajorVersion() + "." - + driver.getMinorVersion()); - } - - if (driver.getMajorVersion() == 10 && isUseOracleImplicitCache()) { - this.getConnectProperties().setProperty("oracle.jdbc.FreeMemoryOnEnterImplicitCache", "true"); - } - - oracleValidationQueryCheck(); - } else if (JdbcUtils.DB2.equals(dbType)) { - db2ValidationQueryCheck(); - } - } - - private void oracleValidationQueryCheck() { - if (validationQuery == null) { - return; - } - if (validationQuery.length() == 0) { - return; - } - - SQLStatementParser sqlStmtParser = SQLParserUtils.createSQLStatementParser(validationQuery, this.dbType); - List stmtList = sqlStmtParser.parseStatementList(); - - if (stmtList.size() != 1) { - return; - } - - SQLStatement stmt = stmtList.get(0); - if (!(stmt instanceof SQLSelectStatement)) { - return; - } - - SQLSelectQuery query = ((SQLSelectStatement) stmt).getSelect().getQuery(); - if (query instanceof SQLSelectQueryBlock) { - if (((SQLSelectQueryBlock) query).getFrom() == null) { - LOG.error("invalid oracle validationQuery. " + validationQuery + ", may should be : " + validationQuery - + " FROM DUAL"); - } - } - } - - private void db2ValidationQueryCheck() { - if (validationQuery == null) { - return; - } - if (validationQuery.length() == 0) { - return; - } - - SQLStatementParser sqlStmtParser = SQLParserUtils.createSQLStatementParser(validationQuery, this.dbType); - List stmtList = sqlStmtParser.parseStatementList(); - - if (stmtList.size() != 1) { - return; - } - - SQLStatement stmt = stmtList.get(0); - if (!(stmt instanceof SQLSelectStatement)) { - return; - } - - SQLSelectQuery query = ((SQLSelectStatement) stmt).getSelect().getQuery(); - if (query instanceof SQLSelectQueryBlock) { - if (((SQLSelectQueryBlock) query).getFrom() == null) { - LOG.error("invalid db2 validationQuery. " + validationQuery + ", may should be : " + validationQuery - + " FROM SYSDUMMY"); - } - } - } - - private void initValidConnectionChecker() { - String realDriverClassName = driver.getClass().getName(); - if (realDriverClassName.equals("com.mysql.jdbc.Driver")) { - this.validConnectionChecker = new MySqlValidConnectionChecker(); - } else if (realDriverClassName.equals("oracle.jdbc.driver.OracleDriver")) { - this.validConnectionChecker = new OracleValidConnectionChecker(); - } else if (realDriverClassName.equals("com.microsoft.jdbc.sqlserver.SQLServerDriver")) { - this.validConnectionChecker = new MSSQLValidConnectionChecker(); - } - } - - private void initExceptionSorter() { - String realDriverClassName = driver.getClass().getName(); - if (realDriverClassName.equals("com.mysql.jdbc.Driver")) { - this.exceptionSorter = new MySqlExceptionSorter(); - } else if (realDriverClassName.equals("oracle.jdbc.driver.OracleDriver")) { - this.exceptionSorter = new OracleExceptionSorter(); - } else if (realDriverClassName.equals("com.informix.jdbc.IfxDriver")) { - this.exceptionSorter = new InformixExceptionSorter(); - - } else if (realDriverClassName.equals("com.sybase.jdbc2.jdbc.SybDriver")) { - this.exceptionSorter = new SybaseExceptionSorter(); - - } else if (realDriverClassName.equals("com.alibaba.druid.mock.MockDriver")) { - this.exceptionSorter = new MockExceptionSorter(); - } - } - - @Override - public DruidPooledConnection getConnection() throws SQLException { - return getConnection(maxWait); - } - - public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException { - init(); - - if (filters.size() > 0) { - FilterChainImpl filterChain = new FilterChainImpl(this); - return filterChain.dataSource_connect(this, maxWaitMillis); - } else { - return getConnectionDirect(maxWaitMillis); - } - } - - @Override - public PooledConnection getPooledConnection() throws SQLException { - return getConnection(maxWait); - } - - @Override - public PooledConnection getPooledConnection(String user, String password) throws SQLException { - throw new UnsupportedOperationException("Not supported by DruidDataSource"); - } - - public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException { - for (;;) { - DruidPooledConnection poolalbeConnection = getConnectionInternal(maxWaitMillis); - - if (isTestOnBorrow()) { - boolean validate = testConnectionInternal(poolalbeConnection.getConnection()); - if (!validate) { - if (LOG.isDebugEnabled()) { - LOG.debug("skip not validate connection."); - } - - Connection realConnection = poolalbeConnection.getConnection(); - discardConnection(realConnection); - continue; - } - } else { - Connection realConnection = poolalbeConnection.getConnection(); - if (realConnection.isClosed()) { - discardConnection(null); // 传入null,避免重复关闭 - continue; - } - - if (isTestWhileIdle()) { - long idleMillis = System.currentTimeMillis() - - poolalbeConnection.getConnectionHolder().getLastActiveTimeMillis(); - if (idleMillis >= this.getTimeBetweenEvictionRunsMillis()) { - boolean validate = testConnectionInternal(poolalbeConnection.getConnection()); - if (!validate) { - if (LOG.isDebugEnabled()) { - LOG.debug("skip not validate connection."); - } - - discardConnection(realConnection); - continue; - } - } - } - } - - if (isRemoveAbandoned()) { - StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - poolalbeConnection.setConnectStackTrace(stackTrace); - poolalbeConnection.setConnectedTimeNano(); - poolalbeConnection.setTraceEnable(true); - - synchronized (activeConnections) { - activeConnections.put(poolalbeConnection, PRESENT); - } - } - - if (!this.isDefaultAutoCommit()) { - poolalbeConnection.setAutoCommit(false); - } - - return poolalbeConnection; - } - } - - /** - * 抛弃连接,不进行回收,而是抛弃 - * - * @param realConnection - * @throws SQLException - */ - public void discardConnection(Connection realConnection) { - JdbcUtils.close(realConnection); - - try { - lock.lockInterruptibly(); - } catch (InterruptedException e) { - LOG.error("interrupt"); - return; - } - try { - activeCount--; - discardCount++; - - if (activeCount <= 0) { - empty.signal(); - } - } finally { - lock.unlock(); - } - } - - private DruidPooledConnection getConnectionInternal(long maxWait) throws SQLException { - if (closed) { - connectErrorCount.incrementAndGet(); - throw new DataSourceClosedException("dataSource already closed at " + new Date(closeTimeMillis)); - } - - if (!enable) { - connectErrorCount.incrementAndGet(); - throw new DataSourceDisableException(); - } - - final long nanos = TimeUnit.MILLISECONDS.toNanos(maxWait); - final int maxWaitThreadCount = getMaxWaitThreadCount(); - - DruidConnectionHolder holder; - try { - lock.lockInterruptibly(); - } catch (InterruptedException e) { - connectErrorCount.incrementAndGet(); - throw new SQLException("interrupt", e); - } - - try { - if (maxWaitThreadCount > 0) { - if (notEmptyWaitThreadCount >= maxWaitThreadCount) { - connectErrorCount.incrementAndGet(); - throw new SQLException("maxWaitThreadCount " + maxWaitThreadCount + ", current wait Thread count " - + lock.getQueueLength()); - } - } - - connectCount++; - - if (maxWait > 0) { - holder = pollLast(nanos); - } else { - holder = takeLast(); - } - - activeCount++; - if (activeCount > activePeak) { - activePeak = activeCount; - activePeakTime = System.currentTimeMillis(); - } - - } catch (InterruptedException e) { - connectErrorCount.incrementAndGet(); - throw new SQLException(e.getMessage(), e); - } catch (SQLException e) { - connectErrorCount.incrementAndGet(); - throw e; - } finally { - lock.unlock(); - } - - holder.incrementUseCount(); - - DruidPooledConnection poolalbeConnection = new DruidPooledConnection(holder); - return poolalbeConnection; - } - - public void handleConnectionException(DruidPooledConnection pooledConnection, Throwable t) throws SQLException { - final DruidConnectionHolder holder = pooledConnection.getConnectionHolder(); - - errorCount.incrementAndGet(); - lastError = t; - lastErrorTimeMillis = System.currentTimeMillis(); - - if (t instanceof SQLException) { - SQLException sqlEx = (SQLException) t; - - // broadcastConnectionError - ConnectionEvent event = new ConnectionEvent(pooledConnection, sqlEx); - for (ConnectionEventListener eventListener : holder.getConnectionEventListeners()) { - eventListener.connectionErrorOccurred(event); - } - - // exceptionSorter.isExceptionFatal - if (exceptionSorter != null && exceptionSorter.isExceptionFatal(sqlEx)) { - if (pooledConnection.isTraceEnable()) { - synchronized (activeConnections) { - if (pooledConnection.isTraceEnable()) { - activeConnections.remove(pooledConnection); - pooledConnection.setTraceEnable(false); - } - } - } - this.discardConnection(holder.getConnection()); - holder.setDiscard(true); - pooledConnection.disable(t); - } - - throw sqlEx; - } else { - throw new SQLException("Error", t); - } - } - - /** - * 回收连接 - */ - protected void recycle(DruidPooledConnection pooledConnection) throws SQLException { - final DruidConnectionHolder holder = pooledConnection.getConnectionHolder(); - - if (holder == null) { - LOG.warn("connectionHolder is null"); - return; - } - - if (pooledConnection.getOwnerThread() != Thread.currentThread()) { - LOG.warn("get/close not same thread"); - } - - final Connection physicalConnection = holder.getConnection(); - - if (pooledConnection.isTraceEnable()) { - synchronized (activeConnections) { - if (pooledConnection.isTraceEnable()) { - Object oldInfo = activeConnections.remove(pooledConnection); - if (oldInfo == null) { - if (LOG.isWarnEnabled()) { - LOG.warn("remove abandonded failed. activeConnections.size " + activeConnections.size()); - } - } - pooledConnection.setTraceEnable(false); - } - } - } - - final boolean isAutoCommit = holder.isUnderlyingAutoCommit(); - final boolean isReadOnly = holder.isUnderlyingReadOnly(); - final boolean testOnReturn = this.isTestOnReturn(); - - try { - // check need to rollback? - if ((!isAutoCommit) && (!isReadOnly)) { - pooledConnection.rollback(); - } - - // reset holder, restore default settings, clear warnings - holder.reset(); - - if (testOnReturn) { - boolean validate = testConnectionInternal(physicalConnection); - if (!validate) { - JdbcUtils.close(physicalConnection); - - destroyCount.incrementAndGet(); - - lock.lockInterruptibly(); - try { - activeCount--; - closeCount++; - } finally { - lock.unlock(); - } - return; - } - } - - if (!enable) { - discardConnection(holder.getConnection()); - return; - } - - final long lastActiveTimeMillis = System.currentTimeMillis(); - lock.lockInterruptibly(); - try { - activeCount--; - closeCount++; - - putLast(holder, lastActiveTimeMillis); - recycleCount++; - } finally { - lock.unlock(); - } - } catch (Throwable e) { - holder.clearStatementCache(); - - if (!holder.isDiscard()) { - this.discardConnection(physicalConnection); - holder.setDiscard(true); - } - - LOG.error("recyle error", e); - recycleErrorCount.incrementAndGet(); - } - } - - public long getRecycleErrorCount() { - return recycleErrorCount.get(); - } - - public void clearStatementCache() throws SQLException { - lock.lock(); - try { - for (int i = 0; i < poolingCount; ++i) { - DruidConnectionHolder conn = connections[i]; - conn.getStatementPool().clear(); - } - } finally { - lock.unlock(); - } - } - - /** - * close datasource - */ - public void close() { - lock.lock(); - try { - if (this.closed) { - return; - } - - if (!this.inited) { - return; - } - - if (logStatsThread != null) { - logStatsThread.interrupt(); - } - - if (createConnectionThread != null) { - createConnectionThread.interrupt(); - } - - if (destoryConnectionThread != null) { - destoryConnectionThread.interrupt(); - } - - for (int i = 0; i < poolingCount; ++i) { - try { - DruidConnectionHolder connHolder = connections[i]; - - for (PreparedStatementHolder stmtHolder : connHolder.getStatementPool().getMap().values()) { - connHolder.getStatementPool().closeRemovedStatement(stmtHolder); - } - connHolder.getStatementPool().getMap().clear(); - - Connection physicalConnection = connHolder.getConnection(); - physicalConnection.close(); - connections[i] = null; - destroyCount.incrementAndGet(); - } catch (Exception ex) { - LOG.warn("close connection error", ex); - } - } - poolingCount = 0; - DruidDataSourceStatManager.removeDataSource(this); - - enable = false; - notEmpty.signalAll(); - notEmptySignalCount++; - - this.closed = true; - this.closeTimeMillis = System.currentTimeMillis(); - - for (Filter filter : filters) { - filter.destory(); - } - } finally { - lock.unlock(); - } - - if (LOG.isInfoEnabled()) { - LOG.info("{dataSource-" + this.getID() + "} closed"); - } - } - - void putLast(DruidConnectionHolder e, long lastActiveTimeMillis) { - e.setLastActiveTimeMillis(lastActiveTimeMillis); - connections[poolingCount++] = e; - - if (poolingCount > poolingPeak) { - poolingPeak = poolingCount; - poolingPeakTime = lastActiveTimeMillis; - } - - notEmpty.signal(); - notEmptySignalCount++; - } - - DruidConnectionHolder takeLast() throws InterruptedException, SQLException { - try { - while (poolingCount == 0) { - empty.signal(); // send signal to CreateThread create connection - notEmptyWaitThreadCount++; - if (notEmptyWaitThreadCount > notEmptyWaitThreadPeak) { - notEmptyWaitThreadPeak = notEmptyWaitThreadCount; - } - try { - notEmpty.await(); // signal by recycle or creator - } finally { - notEmptyWaitThreadCount--; - } - notEmptyWaitCount++; - - if (!enable) { - connectErrorCount.incrementAndGet(); - throw new DataSourceDisableException(); - } - } - } catch (InterruptedException ie) { - notEmpty.signal(); // propagate to non-interrupted thread - notEmptySignalCount++; - throw ie; - } - - poolingCount--; - DruidConnectionHolder last = connections[poolingCount]; - connections[poolingCount] = null; - - return last; - } - - DruidConnectionHolder pollLast(long nanos) throws InterruptedException, SQLException { - long estimate = nanos; - - for (int i = 0;; ++i) { - if (poolingCount == 0) { - empty.signal(); // send signal to CreateThread create connection - - if (estimate <= 0) { - if (this.createError == null) { - throw new GetConnectionTimeoutException(createError); - } else { - throw new GetConnectionTimeoutException(); - } - } - - notEmptyWaitThreadCount++; - if (notEmptyWaitThreadCount > notEmptyWaitThreadPeak) { - notEmptyWaitThreadPeak = notEmptyWaitThreadCount; - } - - try { - long startEstimate = estimate; - estimate = notEmpty.awaitNanos(estimate); // signal by - // recycle or - // creator - notEmptyWaitCount++; - notEmptyWaitNanos += (startEstimate - estimate); - - if (!enable) { - connectErrorCount.incrementAndGet(); - throw new DataSourceDisableException(); - } - } catch (InterruptedException ie) { - notEmpty.signal(); // propagate to non-interrupted thread - notEmptySignalCount++; - throw ie; - } finally { - notEmptyWaitThreadCount--; - } - - if (poolingCount == 0) { - if (estimate > 0) { - continue; - } - - if (createError != null) { - throw new GetConnectionTimeoutException(createError); - } else { - throw new GetConnectionTimeoutException("loopWaitCount " + i + ", wait millis " - + (nanos - estimate) / (1000 * 1000)); - } - } - } - - poolingCount--; - DruidConnectionHolder last = connections[poolingCount]; - connections[poolingCount] = null; - - return last; - } - } - - @Override - public Connection getConnection(String username, String password) throws SQLException { - if (!StringUtils.equals(username, this.username)) { - throw new UnsupportedOperationException("Not supported by DruidDataSource"); - } - - if (!StringUtils.equals(password, this.password)) { - throw new UnsupportedOperationException("Not supported by DruidDataSource"); - } - - return getConnection(); - } - - public long getCreateCount() { - return createCount.get(); - } - - public long getDestroyCount() { - return destroyCount.get(); - } - - public long getConnectCount() { - lock.lock(); - try { - return connectCount; - } finally { - lock.unlock(); - } - } - - public long getCloseCount() { - return closeCount; - } - - public long getConnectErrorCount() { - return connectErrorCount.get(); - } - - @Override - public int getPoolingCount() { - lock.lock(); - try { - return poolingCount; - } finally { - lock.unlock(); - } - } - - public int getPoolingPeak() { - lock.lock(); - try { - return poolingPeak; - } finally { - lock.unlock(); - } - } - - public Date getPoolingPeakTime() { - if (poolingPeakTime <= 0) { - return null; - } - - return new Date(poolingPeakTime); - } - - public long getRecycleCount() { - return recycleCount; - } - - public int getActiveCount() { - lock.lock(); - try { - return activeCount; - } finally { - lock.unlock(); - } - } - - public void logStats() { - final DruidDataSourceStatLogger statLogger = this.statLogger; - if (statLogger == null) { - return; - } - - DruidDataSourceStatValue statValue = getStatValueAndReset(); - - statLogger.log(statValue); - } - - public DruidDataSourceStatValue getStatValueAndReset() { - DruidDataSourceStatValue value = new DruidDataSourceStatValue(); - - lock.lock(); - try { - value.poolingCount = this.poolingCount; - value.poolingPeak = this.poolingPeak; - value.poolingPeakTime = this.poolingPeakTime; - - value.activeCount = this.activeCount; - value.activePeak = this.activePeak; - value.activePeakTime = this.activePeakTime; - - value.connectCount = this.connectCount; - value.closeCount = this.closeCount; - value.waitThreadCount = lock.getWaitQueueLength(notEmpty); - value.notEmptyWaitCount = this.notEmptyWaitCount; - value.notEmptyWaitNanos = this.notEmptyWaitNanos; - - // reset - this.poolingPeak = 0; - this.poolingPeakTime = 0; - this.activePeak = 0; - this.activePeakTime = 0; - this.connectCount = 0; - this.closeCount = 0; - - this.notEmptyWaitCount = 0; - this.notEmptyWaitNanos = 0; - } finally { - lock.unlock(); - } - - value.name = this.getName(); - value.dbType = this.getDbType(); - value.driverClassName = this.getDriverClassName(); - - value.url = this.getUrl(); - value.userName = this.getUsername(); - value.filterClassNames = this.getFilterClassNames(); - - value.initialSize = this.getInitialSize(); - value.minIdle = this.getMinIdle(); - value.maxActive = this.getMaxActive(); - - value.queryTimeout = this.getQueryTimeout(); - value.transactionQueryTimeout = this.getTransactionQueryTimeout(); - value.loginTimeout = this.getLoginTimeout(); - value.validConnectionCheckerClassName = this.getValidConnectionCheckerClassName(); - value.exceptionSorterClassName = this.getExceptionSorterClassName(); - - value.testOnBorrow = this.isTestOnBorrow(); - value.testOnReturn = this.isTestOnReturn(); - value.testWhileIdle = this.isTestWhileIdle(); - - value.defaultAutoCommit = this.isDefaultAutoCommit(); - value.defaultReadOnly = this.isDefaultAutoCommit(); - value.defaultTransactionIsolation = this.getDefaultTransactionIsolation(); - - value.logicConnectErrorCount = connectErrorCount.getAndSet(0); - - value.physicalConnectCount = createCount.getAndSet(0); - value.physicalCloseCount = destroyCount.getAndSet(0); - value.physicalConnectErrorCount = createErrorCount.getAndSet(0); - - value.executeCount = this.executeCount.getAndSet(0); - value.errorCount = errorCount.getAndSet(0); - value.commitCount = commitCount.getAndSet(0); - value.rollbackCount = rollbackCount.getAndSet(0); - - value.pstmtCacheHitCount = cachedPreparedStatementHitCount.getAndSet(0); - value.pstmtCacheMissCount = cachedPreparedStatementMissCount.getAndSet(0); - - value.startTransactionCount = startTransactionCount.getAndSet(0); - value.transactionHistogram = this.getTransactionHistogram().toArrayAndReset(); - - value.connectionHoldTimeHistogram = this.getDataSourceStat().getConnectionHoldHistogram().toArrayAndReset(); - value.removeAbandoned = this.isRemoveAbandoned(); - value.clobOpenCount = this.getDataSourceStat().getClobOpenCountAndReset(); - value.blobOpenCount = this.getDataSourceStat().getBlobOpenCountAndReset(); - - value.sqlSkipCount = this.getDataSourceStat().getSkipSqlCountAndReset(); - value.sqlList = this.getDataSourceStat().getSqlStatMapAndReset(); - - return value; - } - - public long getRemoveAbandonedCount() { - return removeAbandonedCount; - } - - public class CreateConnectionThread extends Thread { - - public CreateConnectionThread(String name){ - super(name); - this.setDaemon(true); - } - - public void run() { - initedLatch.countDown(); - - int errorCount = 0; - for (;;) { - // addLast - try { - lock.lockInterruptibly(); - } catch (InterruptedException e2) { - break; - } - - try { - // 必须存在线程等待,才创建连接 - if (poolingCount >= notEmptyWaitThreadCount) { - empty.await(); - } - - // 防止创建超过maxActive数量的连接 - if (activeCount + poolingCount >= maxActive) { - empty.await(); - continue; - } - - } catch (InterruptedException e) { - lastCreateError = e; - lastErrorTimeMillis = System.currentTimeMillis(); - break; - } finally { - lock.unlock(); - } - - Connection connection = null; - - try { - connection = createPhysicalConnection(); - } catch (SQLException e) { - LOG.error("create connection error", e); - - errorCount++; - - if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) { - if (breakAfterAcquireFailure) { - break; - } - - try { - Thread.sleep(timeBetweenConnectErrorMillis); - } catch (InterruptedException interruptEx) { - break; - } - } - } catch (RuntimeException e) { - LOG.error("create connection error", e); - continue; - } catch (Error e) { - LOG.error("create connection error", e); - break; - } - - if (connection == null) { - continue; - } - - DruidConnectionHolder holder = null; - try { - holder = new DruidConnectionHolder(DruidDataSource.this, connection); - } catch (SQLException ex) { - LOG.error("create connection holder error", ex); - break; - } - - lock.lock(); - try { - connections[poolingCount++] = holder; - - if (poolingCount > poolingPeak) { - poolingPeak = poolingCount; - poolingPeakTime = System.currentTimeMillis(); - } - - errorCount = 0; // reset errorCount - - notEmpty.signal(); - notEmptySignalCount++; - } finally { - lock.unlock(); - } - } - } - } - - public class DestroyConnectionThread extends Thread { - - public DestroyConnectionThread(String name){ - super(name); - this.setDaemon(true); - } - - public void run() { - initedLatch.countDown(); - - for (;;) { - // 从前面开始删除 - try { - if (closed) { - break; - } - - if (timeBetweenEvictionRunsMillis > 0) { - Thread.sleep(timeBetweenEvictionRunsMillis); - } else { - Thread.sleep(1000); // - } - - if (Thread.interrupted()) { - break; - } - - shrink(true); - - if (isRemoveAbandoned()) { - removeAbandoned(); - } - } catch (InterruptedException e) { - break; - } - } - } - - } - - public class LogStatsThread extends Thread { - - public LogStatsThread(String name){ - super(name); - this.setDaemon(true); - } - - public void run() { - try { - for (;;) { - try { - logStats(); - } catch (Exception e) { - LOG.error("logStats error", e); - } - - Thread.sleep(timeBetweenLogStatsMillis); - } - } catch (InterruptedException e) { - // skip - } - } - } - - public int removeAbandoned() { - int removeCount = 0; - - long currrentNanos = System.nanoTime(); - - List abandonedList = new ArrayList(); - - synchronized (activeConnections) { - Iterator iter = activeConnections.keySet().iterator(); - - for (; iter.hasNext();) { - DruidPooledConnection pooledConnection = iter.next(); - - if (pooledConnection.isRunning()) { - continue; - } - - long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000); - - if (timeMillis >= removeAbandonedTimeoutMillis) { - iter.remove(); - pooledConnection.setTraceEnable(false); - abandonedList.add(pooledConnection); - } - } - } - - if (abandonedList.size() > 0) { - for (DruidPooledConnection pooledConnection : abandonedList) { - JdbcUtils.close(pooledConnection); - pooledConnection.abandond(); - removeAbandonedCount++; - removeCount++; - - if (isLogAbandoned()) { - StringBuilder buf = new StringBuilder(); - buf.append("abandon connection, open stackTrace\n"); - - StackTraceElement[] trace = pooledConnection.getConnectStackTrace(); - for (int i = 0; i < trace.length; i++) { - buf.append("\tat "); - buf.append(trace[i].toString()); - buf.append("\n"); - } - - LOG.error(buf.toString()); - } - } - } - - return removeCount; - } - - /** Instance key */ - protected String instanceKey = null; - - public Reference getReference() throws NamingException { - final String className = getClass().getName(); - final String factoryName = className + "Factory"; // XXX: not robust - Reference ref = new Reference(className, factoryName, null); - ref.add(new StringRefAddr("instanceKey", instanceKey)); - ref.add(new StringRefAddr("url", this.getUrl())); - ref.add(new StringRefAddr("username", this.getUsername())); - ref.add(new StringRefAddr("password", this.getPassword())); - // TODO ADD OTHER PROPERTIES - return ref; - } - - @Override - public List getFilterClassNames() { - List names = new ArrayList(); - for (Filter filter : filters) { - names.add(filter.getClass().getName()); - } - return names; - } - - public int getRawDriverMajorVersion() { - int version = -1; - if (this.driver != null) { - version = driver.getMajorVersion(); - } - return version; - } - - public int getRawDriverMinorVersion() { - int version = -1; - if (this.driver != null) { - version = driver.getMinorVersion(); - } - return version; - } - - public String getProperties() { - Properties properties = new Properties(); - properties.putAll(connectProperties); - if (properties.containsKey("password")) { - properties.put("password", "******"); - } - return properties.toString(); - } - - @Override - public void shrink() { - shrink(false); - } - - public void shrink(boolean checkTime) { - final List evictList = new ArrayList(); - try { - lock.lockInterruptibly(); - } catch (InterruptedException e) { - return; - } - - try { - final int checkCount = poolingCount - minIdle; - for (int i = 0; i < checkCount; ++i) { - DruidConnectionHolder connection = connections[i]; - - if (checkTime) { - long idleMillis = System.currentTimeMillis() - connection.getLastActiveTimeMillis(); - if (idleMillis >= minEvictableIdleTimeMillis) { - evictList.add(connection); - } else { - break; - } - } else { - evictList.add(connection); - } - } - - int removeCount = evictList.size(); - if (removeCount > 0) { - System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount); - Arrays.fill(connections, poolingCount - removeCount, poolingCount, null); - poolingCount -= removeCount; - } - } finally { - lock.unlock(); - } - - for (DruidConnectionHolder item : evictList) { - Connection connection = item.getConnection(); - JdbcUtils.close(connection); - destroyCount.incrementAndGet(); - } - } - - public int getWaitThreadCount() { - lock.lock(); - try { - return lock.getWaitQueueLength(notEmpty); - } finally { - lock.unlock(); - } - } - - public long getNotEmptyWaitCount() { - return notEmptyWaitCount; - } - - public int getNotEmptyWaitThreadCount() { - lock.lock(); - try { - return notEmptyWaitThreadCount; - } finally { - lock.unlock(); - } - } - - public int getNotEmptyWaitThreadPeak() { - lock.lock(); - try { - return notEmptyWaitThreadPeak; - } finally { - lock.unlock(); - } - } - - public long getNotEmptySignalCount() { - return notEmptySignalCount; - } - - public long getNotEmptyWaitMillis() { - return notEmptyWaitNanos / (1000 * 1000); - } - - public long getNotEmptyWaitNanos() { - return notEmptyWaitNanos; - } - - public int getLockQueueLength() { - return lock.getQueueLength(); - } - - public int getActivePeak() { - return activePeak; - } - - public Date getActivePeakTime() { - if (activePeakTime <= 0) { - return null; - } - - return new Date(activePeakTime); - } - - public String dump() { - lock.lock(); - try { - return this.toString(); - } finally { - lock.unlock(); - } - } - - public long getErrorCount() { - return this.errorCount.get(); - } - - public String toString() { - StringBuilder buf = new StringBuilder(); - - buf.append("{"); - - buf.append("\n\tCreateTime:\""); - buf.append(IOUtils.toString(getCreatedTime())); - buf.append("\""); - - buf.append(",\n\tActiveCount:"); - buf.append(getActiveCount()); - - buf.append(",\n\tPoolingCount:"); - buf.append(getPoolingCount()); - - buf.append(",\n\tCreateCount:"); - buf.append(getCreateCount()); - - buf.append(",\n\tDestroyCount:"); - buf.append(getDestroyCount()); - - buf.append(",\n\tCloseCount:"); - buf.append(getCloseCount()); - - buf.append(",\n\tConnectCount:"); - buf.append(getConnectCount()); - - buf.append(",\n\tConnections:["); - for (int i = 0; i < poolingCount; ++i) { - DruidConnectionHolder conn = connections[i]; - if (conn != null) { - if (i != 0) { - buf.append(","); - } - buf.append("\n\t\t"); - buf.append(conn.toString()); - } - } - buf.append("\n\t]"); - - buf.append("\n}"); - - if (this.isPoolPreparedStatements()) { - buf.append("\n\n["); - for (int i = 0; i < poolingCount; ++i) { - DruidConnectionHolder conn = connections[i]; - if (conn != null) { - if (i != 0) { - buf.append(","); - } - buf.append("\n\t{\n\tID:"); - buf.append(System.identityHashCode(conn.getConnection())); - PreparedStatementPool pool = conn.getStatementPool(); - - buf.append(", \n\tpoolStatements:["); - - int entryIndex = 0; - try { - for (Map.Entry entry : pool.getMap().entrySet()) { - if (entryIndex != 0) { - buf.append(","); - } - buf.append("\n\t\t{hitCount:"); - buf.append(entry.getValue().getHitCount()); - buf.append(",sql:\""); - buf.append(entry.getKey().getSql()); - buf.append("\""); - buf.append("\t}"); - - entryIndex++; - } - } catch (ConcurrentModificationException e) { - // skip .. - } - - buf.append("\n\t\t]"); - - buf.append("\n\t}"); - } - } - buf.append("\n]"); - } - - return buf.toString(); - } - - public List> getPoolingConnectionInfo() { - List> list = new ArrayList>(); - lock.lock(); - try { - for (int i = 0; i < poolingCount; ++i) { - DruidConnectionHolder connHolder = connections[i]; - Connection conn = connHolder.getConnection(); - - Map map = new LinkedHashMap(); - map.put("id", System.identityHashCode(conn)); - map.put("useCount", connHolder.getUseCount()); - if (connHolder.getLastActiveTimeMillis() > 0) { - map.put("lastActiveTime", new Date(connHolder.getLastActiveTimeMillis())); - } - map.put("connectTime", new Date(connHolder.getTimeMillis())); - map.put("holdability", connHolder.getUnderlyingHoldability()); - map.put("transactionIsolation", connHolder.getUnderlyingTransactionIsolation()); - map.put("autoCommit", connHolder.isUnderlyingAutoCommit()); - map.put("readoOnly", connHolder.isUnderlyingReadOnly()); - - if (connHolder.isPoolPreparedStatements()) { - List> stmtCache = new ArrayList>(); - PreparedStatementPool stmtPool = connHolder.getStatementPool(); - for (PreparedStatementHolder stmtHolder : stmtPool.getMap().values()) { - Map stmtInfo = new LinkedHashMap(); - - stmtInfo.put("sql", stmtHolder.getKey().getSql()); - stmtInfo.put("defaultRowPretch", stmtHolder.getDefaultRowPretch()); - stmtInfo.put("rowPrefetch", stmtHolder.getRowPrefetch()); - stmtInfo.put("hitCount", stmtHolder.getHitCount()); - - stmtCache.add(stmtInfo); - } - - map.put("pscache", stmtCache); - } - - list.add(map); - } - } finally { - lock.unlock(); - } - return list; - } - - public void logTransaction(TransactionInfo info) { - long transactionMillis = info.getEndTimeMillis() - info.getStartTimeMillis(); - if (transactionThresholdMillis > 0 && transactionMillis > transactionThresholdMillis) { - StringBuilder buf = new StringBuilder(); - buf.append("long time transaction, take "); - buf.append(transactionMillis); - buf.append(" ms : "); - for (String sql : info.getSqlList()) { - buf.append(sql); - buf.append(";"); - } - LOG.error(buf.toString(), new TransactionTimeoutException()); - } - } - - @Override - public String getVersion() { - return VERSION.getVersionNumber(); - } - - @Override - public JdbcDataSourceStat getDataSourceStat() { - return dataSourceStat; - } - - public Object clone() throws CloneNotSupportedException { - return cloneDruidDataSource(); - } - - public DruidDataSource cloneDruidDataSource() { - DruidDataSource x = new DruidDataSource(); - - cloneTo(x); - - return x; - } - - public Map getStatDataForMBean() { - try { - Map map = new HashMap(); - - // 0 - 4 - map.put("Name", this.getName()); - map.put("URL", this.getUrl()); - map.put("CreateCount", this.getCreateCount()); - map.put("DestroyCount", this.getDestroyCount()); - map.put("ConnectCount", this.getConnectCount()); - - // 5 - 9 - map.put("CloseCount", this.getCloseCount()); - map.put("ActiveCount", this.getActivePeak()); - map.put("PoolingCount", this.getPoolingCount()); - map.put("LockQueueLength", this.getLockQueueLength()); - map.put("WaitThreadCount", this.getNotEmptyWaitThreadPeak()); - - // 10 - 14 - map.put("InitialSize", this.getInitialSize()); - map.put("MaxActive", this.getMaxActive()); - map.put("MinIdle", this.getMinIdle()); - map.put("PoolPreparedStatements", this.isPoolPreparedStatements()); - map.put("TestOnBorrow", this.isTestOnBorrow()); - - // 15 - 19 - map.put("TestOnReturn", this.isTestOnReturn()); - map.put("MinEvictableIdleTimeMillis", this.getMinEvictableIdleTimeMillis()); - map.put("ConnectErrorCount", this.getConnectErrorCount()); - map.put("CreateTimespanMillis", this.getCreateTimespanMillis()); - map.put("DbType", this.getDbType()); - - // 20 - 24 - map.put("ValidationQuery", this.getValidationQuery()); - map.put("ValidationQueryTimeout", this.getValidationQueryTimeout()); - map.put("DriverClassName", this.getDriverClassName()); - map.put("Username", this.getUsername()); - map.put("RemoveAbandonedCount", this.getRemoveAbandonedCount()); - - // 25 - 29 - map.put("NotEmptyWaitCount", this.getNotEmptyWaitCount()); - map.put("NotEmptyWaitNanos", this.getNotEmptyWaitNanos()); - map.put("ErrorCount", this.getErrorCount()); - map.put("ReusePreparedStatementCount", this.getCachedPreparedStatementHitCount()); - map.put("StartTransactionCount", this.getStartTransactionCount()); - - // 30 - 34 - map.put("CommitCount", this.getCommitCount()); - map.put("RollbackCount", this.getRollbackCount()); - map.put("LastError", JMXUtils.getErrorCompositeData(this.getLastError())); - map.put("LastCreateError", JMXUtils.getErrorCompositeData(this.getLastCreateError())); - map.put("PreparedStatementCacheDeleteCount", this.getCachedPreparedStatementDeleteCount()); - - // 35 - 39 - map.put("PreparedStatementCacheAccessCount", this.getCachedPreparedStatementAccessCount()); - map.put("PreparedStatementCacheMissCount", this.getCachedPreparedStatementMissCount()); - map.put("PreparedStatementCacheHitCount", this.getCachedPreparedStatementHitCount()); - map.put("PreparedStatementCacheCurrentCount", this.getCachedPreparedStatementCount()); - map.put("Version", this.getVersion()); - - // 40 - - map.put("LastErrorTime", this.getLastErrorTime()); - map.put("LastCreateErrorTime", this.getLastCreateErrorTime()); - map.put("CreateErrorCount", this.getCreateErrorCount()); - map.put("DiscardCount", this.getDiscardCount()); - - return map; - } catch (JMException ex) { - throw new IllegalStateException("getStatData error", ex); - } - } - - public Map getStatData() { - final int activeCount; - final int activePeak; - final Date activePeakTime; - - final int poolingCount; - final int poolingPeak; - final Date poolingPeakTime; - - final long connectCount; - final long closeCount; - - lock.lock(); - try { - poolingCount = this.poolingCount; - poolingPeak = this.poolingPeak; - poolingPeakTime = this.getPoolingPeakTime(); - - activeCount = this.activeCount; - activePeak = this.activePeak; - activePeakTime = this.getActivePeakTime(); - - connectCount = this.connectCount; - closeCount = this.closeCount; - } finally { - lock.unlock(); - } - Map dataMap = new LinkedHashMap(); - - dataMap.put("Identity", System.identityHashCode(this)); - dataMap.put("Name", this.getName()); - dataMap.put("DbType", this.getDbType()); - dataMap.put("DriverClassName", this.getDriverClassName()); - - dataMap.put("URL", this.getUrl()); - dataMap.put("UserName", this.getUsername()); - dataMap.put("FilterClassNames", this.getFilterClassNames()); - - dataMap.put("WaitThreadCount", this.getWaitThreadCount()); - dataMap.put("NotEmptyWaitCount", this.getNotEmptyWaitCount()); - dataMap.put("NotEmptyWaitMillis", this.getNotEmptyWaitMillis()); - - dataMap.put("PoolingCount", poolingCount); - dataMap.put("PoolingPeak", poolingPeak); - dataMap.put("PoolingPeakTime", poolingPeakTime); - - dataMap.put("ActiveCount", activeCount); - dataMap.put("ActivePeak", activePeak); - dataMap.put("ActivePeakTime", activePeakTime); - - dataMap.put("InitialSize", this.getInitialSize()); - dataMap.put("MinIdle", this.getMinIdle()); - dataMap.put("MaxActive", this.getMaxActive()); - - dataMap.put("QueryTimeout", this.getQueryTimeout()); - dataMap.put("TransactionQueryTimeout", this.getTransactionQueryTimeout()); - dataMap.put("LoginTimeout", this.getLoginTimeout()); - dataMap.put("ValidConnectionCheckerClassName", this.getValidConnectionCheckerClassName()); - dataMap.put("ExceptionSorterClassName", this.getExceptionSorterClassName()); - - dataMap.put("TestOnBorrow", this.isTestOnBorrow()); - dataMap.put("TestOnReturn", this.isTestOnReturn()); - dataMap.put("TestWhileIdle", this.isTestWhileIdle()); - - dataMap.put("DefaultAutoCommit", this.isDefaultAutoCommit()); - dataMap.put("DefaultReadOnly", this.isDefaultAutoCommit()); - dataMap.put("DefaultTransactionIsolation", this.getDefaultTransactionIsolation()); - - dataMap.put("LogicConnectCount", connectCount); - dataMap.put("LogicCloseCount", closeCount); - dataMap.put("LogicConnectErrorCount", this.getConnectErrorCount()); - - dataMap.put("PhysicalConnectCount", this.getCreateCount()); - dataMap.put("PhysicalCloseCount", this.getDestroyCount()); - dataMap.put("PhysicalConnectErrorCount", this.getCreateErrorCount()); - - dataMap.put("ExecuteCount", this.getExecuteCount()); - dataMap.put("ErrorCount", this.getErrorCount()); - dataMap.put("CommitCount", this.getCommitCount()); - dataMap.put("RollbackCount", this.getRollbackCount()); - - dataMap.put("PSCacheAccessCount", this.getCachedPreparedStatementAccessCount()); - dataMap.put("PSCacheHitCount", this.getCachedPreparedStatementHitCount()); - dataMap.put("PSCacheMissCount", this.getCachedPreparedStatementMissCount()); - - dataMap.put("StartTransactionCount", this.getStartTransactionCount()); - dataMap.put("TransactionHistogram", this.getTransactionHistogramValues()); - - dataMap.put("ConnectionHoldTimeHistogram", this.getDataSourceStat().getConnectionHoldHistogram().toArray()); - dataMap.put("RemoveAbandoned", this.isRemoveAbandoned()); - dataMap.put("ClobOpenCount", this.getDataSourceStat().getClobOpenCount()); - dataMap.put("BlobOpenCount", this.getDataSourceStat().getBlobOpenCount()); - - return dataMap; - } - - public JdbcSqlStat getSqlStat(int sqlId) { - return this.getDataSourceStat().getSqlStat(sqlId); - } - - public JdbcSqlStat getSqlStat(long sqlId) { - return this.getDataSourceStat().getSqlStat(sqlId); - } - - public Map getSqlStatMap() { - return this.getDataSourceStat().getSqlStatMap(); - } - - public Map getWallStatMap() { - for (Filter filter : this.filters) { - if (filter instanceof WallFilter) { - WallFilter wallFilter = (WallFilter) filter; - return wallFilter.getProvider().getStatsMap(); - } - } - - return null; - } - - public Lock getLock() { - return lock; - } - - @Override - public boolean isWrapperFor(Class iface) { - for (Filter filter : this.filters) { - if (filter.isWrapperFor(iface)) { - return true; - } - } - - return super.isWrapperFor(iface); - } - - @SuppressWarnings("unchecked") - public T unwrap(Class iface) { - for (Filter filter : this.filters) { - if (filter.isWrapperFor(iface)) { - return (T) filter; - } - } - - return super.unwrap(iface); - } -} +/* + * Copyright 1999-2011 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.io.Closeable; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.ConcurrentModificationException; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.ServiceLoader; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import javax.management.JMException; +import javax.management.ObjectName; +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.Referenceable; +import javax.naming.StringRefAddr; +import javax.sql.ConnectionEvent; +import javax.sql.ConnectionEventListener; +import javax.sql.ConnectionPoolDataSource; +import javax.sql.PooledConnection; + +import com.alibaba.druid.Constants; +import com.alibaba.druid.TransactionTimeoutException; +import com.alibaba.druid.VERSION; +import com.alibaba.druid.filter.AutoLoad; +import com.alibaba.druid.filter.Filter; +import com.alibaba.druid.filter.FilterChainImpl; +import com.alibaba.druid.mock.MockDriver; +import com.alibaba.druid.pool.DruidPooledPreparedStatement.PreparedStatementKey; +import com.alibaba.druid.pool.vendor.InformixExceptionSorter; +import com.alibaba.druid.pool.vendor.MSSQLValidConnectionChecker; +import com.alibaba.druid.pool.vendor.MockExceptionSorter; +import com.alibaba.druid.pool.vendor.MySqlExceptionSorter; +import com.alibaba.druid.pool.vendor.MySqlValidConnectionChecker; +import com.alibaba.druid.pool.vendor.OracleExceptionSorter; +import com.alibaba.druid.pool.vendor.OracleValidConnectionChecker; +import com.alibaba.druid.pool.vendor.SybaseExceptionSorter; +import com.alibaba.druid.proxy.DruidDriver; +import com.alibaba.druid.proxy.jdbc.DataSourceProxyConfig; +import com.alibaba.druid.proxy.jdbc.TransactionInfo; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.parser.SQLParserUtils; +import com.alibaba.druid.sql.parser.SQLStatementParser; +import com.alibaba.druid.stat.DruidDataSourceStatManager; +import com.alibaba.druid.stat.JdbcDataSourceStat; +import com.alibaba.druid.stat.JdbcSqlStat; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; +import com.alibaba.druid.util.IOUtils; +import com.alibaba.druid.util.JMXUtils; +import com.alibaba.druid.util.JdbcConstants; +import com.alibaba.druid.util.JdbcUtils; +import com.alibaba.druid.util.StringUtils; +import com.alibaba.druid.wall.WallFilter; + +; +/** + * @author ljw + * @author wenshao + */ +public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource { + + private final static Log LOG = LogFactory.getLog(DruidDataSource.class); + + private static final long serialVersionUID = 1L; + + // stats + private final AtomicLong recycleErrorCount = new AtomicLong(); + private long connectCount = 0L; + private long closeCount = 0L; + private final AtomicLong connectErrorCount = new AtomicLong(); + private long recycleCount = 0L; + private long removeAbandonedCount = 0L; + private long notEmptyWaitCount = 0L; + private long notEmptySignalCount = 0L; + private long notEmptyWaitNanos = 0L; + + private int activePeak = 0; + private long activePeakTime = 0; + private int poolingPeak = 0; + private long poolingPeakTime = 0; + + // store + private volatile DruidConnectionHolder[] connections; + private int poolingCount = 0; + private int activeCount = 0; + private long discardCount = 0; + private int notEmptyWaitThreadCount = 0; + private int notEmptyWaitThreadPeak = 0; + + // threads + private CreateConnectionThread createConnectionThread; + private DestroyConnectionThread destoryConnectionThread; + private LogStatsThread logStatsThread; + + private final CountDownLatch initedLatch = new CountDownLatch(2); + + private volatile boolean enable = true; + + private boolean resetStatEnable = true; + + private String initStackTrace; + + private volatile boolean closed = false; + private long closeTimeMillis = -1L; + + protected JdbcDataSourceStat dataSourceStat; + + private boolean useGloalDataSourceStat = false; + + public DruidDataSource(){ + this(false); + } + + public DruidDataSource(boolean fairLock){ + super(fairLock); + + configFromPropety(System.getProperties()); + } + + public void configFromPropety(Properties properties) { + { + String property = properties.getProperty("druid.testWhileIdle"); + if ("true".equals(property)) { + this.setTestWhileIdle(true); + } else if ("false".equals(property)) { + this.setTestWhileIdle(false); + } + } + { + String property = properties.getProperty("druid.testOnBorrow"); + if ("true".equals(property)) { + this.setTestOnBorrow(true); + } else if ("false".equals(property)) { + this.setTestOnBorrow(false); + } + } + { + String property = properties.getProperty("druid.validationQuery"); + if (property != null && property.length() > 0) { + this.setValidationQuery(property); + } + } + { + String property = properties.getProperty("druid.useGloalDataSourceStat"); + if ("true".equals(property)) { + this.setUseGloalDataSourceStat(true); + } else if ("false".equals(property)) { + this.setUseGloalDataSourceStat(false); + } + } + { + String property = properties.getProperty("druid.filters"); + + if (property != null && property.length() > 0) { + try { + this.setFilters(property); + } catch (SQLException e) { + LOG.error("setFilters error", e); + } + } + } + { + String property = properties.getProperty(Constants.DRUID_TIME_BETWEEN_LOG_STATS_MILLIS); + if (property != null && property.length() > 0) { + try { + long value = Long.parseLong(property); + this.setTimeBetweenLogStatsMillis(value); + } catch (NumberFormatException e) { + LOG.error("illegal property '" + Constants.DRUID_TIME_BETWEEN_LOG_STATS_MILLIS + "'", e); + } + } + } + { + String property = properties.getProperty(Constants.DRUID_STAT_SQL_MAX_SIZE); + if (property != null && property.length() > 0) { + try { + int value = Integer.parseInt(property); + if (dataSourceStat != null) { + dataSourceStat.setMaxSqlSize(value); + } + } catch (NumberFormatException e) { + LOG.error("illegal property '" + Constants.DRUID_STAT_SQL_MAX_SIZE + "'", e); + } + } + } + } + + public boolean isUseGloalDataSourceStat() { + return useGloalDataSourceStat; + } + + public void setUseGloalDataSourceStat(boolean useGloalDataSourceStat) { + this.useGloalDataSourceStat = useGloalDataSourceStat; + } + + public String getInitStackTrace() { + return initStackTrace; + } + + public boolean isResetStatEnable() { + return resetStatEnable; + } + + public void setResetStatEnable(boolean resetStatEnable) { + this.resetStatEnable = resetStatEnable; + } + + public long getDiscardCount() { + return discardCount; + } + + public void restart() { + lock.lock(); + try { + if (LOG.isInfoEnabled()) { + LOG.info("{dataSource-" + this.getID() + "} restart"); + } + + this.close(); + this.resetStat(); + this.inited = false; + this.enable = true; + this.closed = false; + } finally { + lock.unlock(); + } + } + + public void resetStat() { + if (!resetStatEnable) { + return; + } + + lock.lock(); + try { + connectCount = 0; + closeCount = 0; + discardCount = 0; + recycleCount = 0; + createCount.set(0); + destroyCount.set(0); + removeAbandonedCount = 0; + notEmptyWaitCount = 0; + notEmptySignalCount = 0L; + notEmptyWaitNanos = 0; + + activePeak = 0; + activePeakTime = 0; + poolingPeak = 0; + createTimespan = 0; + lastError = null; + lastErrorTimeMillis = 0; + lastCreateError = null; + lastCreateErrorTimeMillis = 0; + } finally { + lock.unlock(); + } + + connectErrorCount.set(0); + errorCount.set(0); + commitCount.set(0); + rollbackCount.set(0); + startTransactionCount.set(0); + cachedPreparedStatementHitCount.set(0); + closedPreparedStatementCount.set(0); + preparedStatementCount.set(0); + transactionHistogram.reset(); + cachedPreparedStatementDeleteCount.set(0); + recycleErrorCount.set(0); + } + + public boolean isEnable() { + return enable; + } + + public void setEnable(boolean enable) { + lock.lock(); + try { + this.enable = enable; + if (!enable) { + notEmpty.signalAll(); + notEmptySignalCount++; + } + } finally { + lock.unlock(); + } + } + + public void setPoolPreparedStatements(boolean value) { + if (this.poolPreparedStatements == value) { + return; + } + + this.poolPreparedStatements = value; + + if (!inited) { + return; + } + + if (LOG.isInfoEnabled()) { + LOG.info("set poolPreparedStatements " + this.poolPreparedStatements + " -> " + value); + } + + if (!value) { + lock.lock(); + try { + + for (int i = 0; i < poolingCount; ++i) { + DruidConnectionHolder connection = connections[i]; + + for (PreparedStatementHolder holder : connection.getStatementPool().getMap().values()) { + closePreapredStatement(holder); + } + + connection.getStatementPool().getMap().clear(); + } + } finally { + lock.unlock(); + } + } + } + + public void setMaxActive(int maxActive) { + if (this.maxActive == maxActive) { + return; + } + + if (maxActive == 0) { + throw new IllegalArgumentException("maxActive can't not set zero"); + } + + if (!inited) { + this.maxActive = maxActive; + return; + } + + if (maxActive < this.minIdle) { + throw new IllegalArgumentException("maxActive less than minIdle, " + maxActive + " < " + this.minIdle); + } + + if (LOG.isInfoEnabled()) { + LOG.info("maxActive changed : " + this.maxActive + " -> " + maxActive); + } + + lock.lock(); + try { + int allCount = this.poolingCount + this.activeCount; + + if (maxActive > allCount) { + this.connections = Arrays.copyOf(this.connections, maxActive); + } else { + this.connections = Arrays.copyOf(this.connections, allCount); + } + + this.maxActive = maxActive; + } finally { + lock.unlock(); + } + } + + @SuppressWarnings("rawtypes") + public void setConnectProperties(Properties properties) { + if (properties == null) { + properties = new Properties(); + } + + boolean equals; + if (properties.size() == this.connectProperties.size()) { + equals = true; + for (Map.Entry entry : properties.entrySet()) { + Object value = this.connectProperties.get(entry.getKey()); + Object entryValue = entry.getValue(); + if (value == null && entryValue != null) { + equals = false; + break; + } + + if (!value.equals(entry.getValue())) { + equals = false; + break; + } + } + } else { + equals = false; + } + + if (!equals) { + if (inited && LOG.isInfoEnabled()) { + LOG.info("connectProperties changed : " + this.connectProperties + " -> " + properties); + } + + configFromPropety(properties); + + for (Filter filter : this.filters) { + filter.configFromProperties(properties); + } + + if (exceptionSorter != null) { + exceptionSorter.configFromProperties(properties); + } + + if (validConnectionChecker != null) { + validConnectionChecker.configFromProperties(properties); + } + + if (statLogger != null) { + statLogger.configFromProperties(properties); + } + } + + this.connectProperties = properties; + } + + public boolean isInited() { + return this.inited; + } + + public void init() throws SQLException { + if (inited) { + return; + } + + final ReentrantLock lock = this.lock; + try { + lock.lockInterruptibly(); + } catch (InterruptedException e) { + throw new SQLException("interrupt", e); + } + + boolean init = false; + try { + if (inited) { + return; + } + + init = true; + + initStackTrace = IOUtils.toString(Thread.currentThread().getStackTrace()); + + this.id = DruidDriver.createDataSourceId(); + + if (this.dbType == null || this.dbType.length() == 0) { + this.dbType = JdbcUtils.getDbType(jdbcUrl, null); + } + + for (Filter filter : filters) { + filter.init(this); + } + + if (JdbcConstants.MYSQL.equals(this.dbType) || // + JdbcConstants.MARIADB.equals(this.dbType)) { + boolean cacheServerConfigurationSet = false; + if (this.connectProperties.containsKey("cacheServerConfiguration")) { + cacheServerConfigurationSet = true; + } else if (this.jdbcUrl.indexOf("cacheServerConfiguration") != -1) { + cacheServerConfigurationSet = true; + } + if (cacheServerConfigurationSet) { + this.connectProperties.put("cacheServerConfiguration", "true"); + } + } + + if (maxActive <= 0) { + throw new IllegalArgumentException("illegal maxActive " + maxActive); + } + + if (maxActive < minIdle) { + throw new IllegalArgumentException("illegal maxActive " + maxActive); + } + + if (getInitialSize() > maxActive) { + throw new IllegalArgumentException("illegal initialSize " + this.initialSize + ", maxActieve " + + maxActive); + } + + if (timeBetweenLogStatsMillis > 0 && useGloalDataSourceStat) { + throw new IllegalArgumentException("timeBetweenLogStatsMillis not support useGloalDataSourceStat=true"); + } + + if (this.driverClass != null) { + this.driverClass = driverClass.trim(); + } + + validationQueryCheck(); + + if (this.jdbcUrl != null) { + this.jdbcUrl = this.jdbcUrl.trim(); + initFromWrapDriverUrl(); + } + + initFromSPIServiceLoader(); + + if (this.driver == null) { + if (this.driverClass == null || this.driverClass.isEmpty()) { + this.driverClass = JdbcUtils.getDriverClassName(this.jdbcUrl); + } + + if (MockDriver.class.getName().equals(driverClass)) { + driver = MockDriver.instance; + } else { + driver = JdbcUtils.createDriver(driverClassLoader, driverClass); + } + } else { + if (this.driverClass == null) { + this.driverClass = driver.getClass().getName(); + } + } + + if (this.dbType == null || this.dbType.length() == 0) { + this.dbType = JdbcUtils.getDbType(jdbcUrl, driverClass.getClass().getName()); + } + + initCheck(); + + initExceptionSorter(); + initValidConnectionChecker(); + + if (isUseGloalDataSourceStat()) { + dataSourceStat = JdbcDataSourceStat.getGlobal(); + if (dataSourceStat == null) { + dataSourceStat = new JdbcDataSourceStat("Global", "Global", this.dbType); + JdbcDataSourceStat.setGlobal(dataSourceStat); + } + if (dataSourceStat.getDbType() == null) { + dataSourceStat.setDbType(this.getDbType()); + } + } else { + dataSourceStat = new JdbcDataSourceStat(this.name, this.jdbcUrl, this.dbType, this.connectProperties); + } + + connections = new DruidConnectionHolder[maxActive]; + + SQLException connectError = null; + + try { + // init connections + for (int i = 0, size = getInitialSize(); i < size; ++i) { + Connection conn = createPhysicalConnection(); + DruidConnectionHolder holder = new DruidConnectionHolder(this, conn); + connections[poolingCount++] = holder; + } + + if (poolingCount > 0) { + poolingPeak = poolingCount; + poolingPeakTime = System.currentTimeMillis(); + } + } catch (SQLException ex) { + LOG.error("init datasource error", ex); + connectError = ex; + } + + createAndLogThread(); + createAndStartCreatorThread(); + createAndStartDestroyThread(); + + initedLatch.await(); + + initedTime = new Date(); + ObjectName objectName = DruidDataSourceStatManager.addDataSource(this, this.name); + this.setObjectName(objectName); + + if (connectError != null && poolingCount == 0) { + throw connectError; + } + } catch (SQLException e) { + LOG.error("dataSource init error", e); + throw e; + } catch (InterruptedException e) { + throw new SQLException(e.getMessage(), e); + } finally { + inited = true; + lock.unlock(); + + if (init && LOG.isInfoEnabled()) { + LOG.info("{dataSource-" + this.getID() + "} inited"); + } + } + } + + private void createAndLogThread() { + if (this.timeBetweenLogStatsMillis <= 0) { + return; + } + + String threadName = "Druid-ConnectionPool-Log-" + System.identityHashCode(this); + logStatsThread = new LogStatsThread(threadName); + logStatsThread.start(); + } + + private void createAndStartDestroyThread() { + String threadName = "Druid-ConnectionPool-Destory-" + System.identityHashCode(this); + destoryConnectionThread = new DestroyConnectionThread(threadName); + destoryConnectionThread.start(); + } + + protected void createAndStartCreatorThread() { + String threadName = "Druid-ConnectionPool-Create-" + System.identityHashCode(this); + createConnectionThread = new CreateConnectionThread(threadName); + createConnectionThread.start(); + } + + /** + * load filters from SPI ServiceLoader + * + * @see ServiceLoader + */ + private void initFromSPIServiceLoader() { + + String property = System.getProperty("druid.load.spifilter.skip"); + if (property != null) { + return; + } + + ServiceLoader druidAutoFilterLoader = ServiceLoader.load(Filter.class); + + for (Filter autoFilter : druidAutoFilterLoader) { + AutoLoad autoLoad = autoFilter.getClass().getAnnotation(AutoLoad.class); + if (autoLoad != null && autoLoad.value()) { + if (LOG.isInfoEnabled()) { + LOG.info("load filter from spi :" + autoFilter.getClass().getName()); + } + addFilter(autoFilter); + } + } + } + + private void initFromWrapDriverUrl() throws SQLException { + if (!jdbcUrl.startsWith(DruidDriver.DEFAULT_PREFIX)) { + return; + } + + DataSourceProxyConfig config = DruidDriver.parseConfig(jdbcUrl, null); + this.driverClass = config.getRawDriverClassName(); + + LOG.error("error url : '" + jdbcUrl + "', it should be : '" + config.getRawUrl() + "'"); + + this.jdbcUrl = config.getRawUrl(); + if (this.name == null) { + this.name = config.getName(); + } + + for (Filter filter : config.getFilters()) { + addFilter(filter); + } + } + + /** + * 会去重复 + * + * @param filter + */ + private void addFilter(Filter filter) { + boolean exists = false; + for (Filter initedFilter : this.filters) { + if (initedFilter.getClass() == filter.getClass()) { + exists = true; + break; + } + } + + if (!exists) { + filter.init(this); + this.filters.add(filter); + } + + } + + private void validationQueryCheck() { + if (!(isTestOnBorrow() || isTestOnReturn() || isTestWhileIdle())) { + return; + } + + if (this.validConnectionChecker != null) { + return; + } + + if (this.getValidationQuery() != null && this.getValidationQuery().length() > 0) { + return; + } + + String errorMessage = ""; + + if (isTestOnBorrow()) { + errorMessage += "testOnBorrow is true, "; + } + + if (isTestOnReturn()) { + errorMessage += "testOnReturn is true, "; + } + + if (isTestWhileIdle()) { + errorMessage += "testWhileIdle is true, "; + } + + LOG.error(errorMessage + "validationQuery not set"); + } + + protected void initCheck() throws SQLException { + if (JdbcUtils.ORACLE.equals(this.dbType)) { + isOracle = true; + + if (driver.getMajorVersion() < 10) { + throw new SQLException("not support oracle driver " + driver.getMajorVersion() + "." + + driver.getMinorVersion()); + } + + if (driver.getMajorVersion() == 10 && isUseOracleImplicitCache()) { + this.getConnectProperties().setProperty("oracle.jdbc.FreeMemoryOnEnterImplicitCache", "true"); + } + + oracleValidationQueryCheck(); + } else if (JdbcUtils.DB2.equals(dbType)) { + db2ValidationQueryCheck(); + } + } + + private void oracleValidationQueryCheck() { + if (validationQuery == null) { + return; + } + if (validationQuery.length() == 0) { + return; + } + + SQLStatementParser sqlStmtParser = SQLParserUtils.createSQLStatementParser(validationQuery, this.dbType); + List stmtList = sqlStmtParser.parseStatementList(); + + if (stmtList.size() != 1) { + return; + } + + SQLStatement stmt = stmtList.get(0); + if (!(stmt instanceof SQLSelectStatement)) { + return; + } + + SQLSelectQuery query = ((SQLSelectStatement) stmt).getSelect().getQuery(); + if (query instanceof SQLSelectQueryBlock) { + if (((SQLSelectQueryBlock) query).getFrom() == null) { + LOG.error("invalid oracle validationQuery. " + validationQuery + ", may should be : " + validationQuery + + " FROM DUAL"); + } + } + } + + private void db2ValidationQueryCheck() { + if (validationQuery == null) { + return; + } + if (validationQuery.length() == 0) { + return; + } + + SQLStatementParser sqlStmtParser = SQLParserUtils.createSQLStatementParser(validationQuery, this.dbType); + List stmtList = sqlStmtParser.parseStatementList(); + + if (stmtList.size() != 1) { + return; + } + + SQLStatement stmt = stmtList.get(0); + if (!(stmt instanceof SQLSelectStatement)) { + return; + } + + SQLSelectQuery query = ((SQLSelectStatement) stmt).getSelect().getQuery(); + if (query instanceof SQLSelectQueryBlock) { + if (((SQLSelectQueryBlock) query).getFrom() == null) { + LOG.error("invalid db2 validationQuery. " + validationQuery + ", may should be : " + validationQuery + + " FROM SYSDUMMY"); + } + } + } + + private void initValidConnectionChecker() { + String realDriverClassName = driver.getClass().getName(); + if (realDriverClassName.equals("com.mysql.jdbc.Driver")) { + this.validConnectionChecker = new MySqlValidConnectionChecker(); + } else if (realDriverClassName.equals("oracle.jdbc.driver.OracleDriver")) { + this.validConnectionChecker = new OracleValidConnectionChecker(); + } else if (realDriverClassName.equals("com.microsoft.jdbc.sqlserver.SQLServerDriver")) { + this.validConnectionChecker = new MSSQLValidConnectionChecker(); + } + } + + private void initExceptionSorter() { + String realDriverClassName = driver.getClass().getName(); + if (realDriverClassName.equals("com.mysql.jdbc.Driver")) { + this.exceptionSorter = new MySqlExceptionSorter(); + } else if (realDriverClassName.equals("oracle.jdbc.driver.OracleDriver")) { + this.exceptionSorter = new OracleExceptionSorter(); + } else if (realDriverClassName.equals("com.informix.jdbc.IfxDriver")) { + this.exceptionSorter = new InformixExceptionSorter(); + + } else if (realDriverClassName.equals("com.sybase.jdbc2.jdbc.SybDriver")) { + this.exceptionSorter = new SybaseExceptionSorter(); + + } else if (realDriverClassName.equals("com.alibaba.druid.mock.MockDriver")) { + this.exceptionSorter = new MockExceptionSorter(); + } + } + + @Override + public DruidPooledConnection getConnection() throws SQLException { + return getConnection(maxWait); + } + + public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException { + init(); + + if (filters.size() > 0) { + FilterChainImpl filterChain = new FilterChainImpl(this); + return filterChain.dataSource_connect(this, maxWaitMillis); + } else { + return getConnectionDirect(maxWaitMillis); + } + } + + @Override + public PooledConnection getPooledConnection() throws SQLException { + return getConnection(maxWait); + } + + @Override + public PooledConnection getPooledConnection(String user, String password) throws SQLException { + throw new UnsupportedOperationException("Not supported by DruidDataSource"); + } + + public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException { + for (;;) { + DruidPooledConnection poolalbeConnection = getConnectionInternal(maxWaitMillis); + + if (isTestOnBorrow()) { + boolean validate = testConnectionInternal(poolalbeConnection.getConnection()); + if (!validate) { + if (LOG.isDebugEnabled()) { + LOG.debug("skip not validate connection."); + } + + Connection realConnection = poolalbeConnection.getConnection(); + discardConnection(realConnection); + continue; + } + } else { + Connection realConnection = poolalbeConnection.getConnection(); + if (realConnection.isClosed()) { + discardConnection(null); // 传入null,避免重复关闭 + continue; + } + + if (isTestWhileIdle()) { + long idleMillis = System.currentTimeMillis() + - poolalbeConnection.getConnectionHolder().getLastActiveTimeMillis(); + if (idleMillis >= this.getTimeBetweenEvictionRunsMillis()) { + boolean validate = testConnectionInternal(poolalbeConnection.getConnection()); + if (!validate) { + if (LOG.isDebugEnabled()) { + LOG.debug("skip not validate connection."); + } + + discardConnection(realConnection); + continue; + } + } + } + } + + if (isRemoveAbandoned()) { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + poolalbeConnection.setConnectStackTrace(stackTrace); + poolalbeConnection.setConnectedTimeNano(); + poolalbeConnection.setTraceEnable(true); + + synchronized (activeConnections) { + activeConnections.put(poolalbeConnection, PRESENT); + } + } + + if (!this.isDefaultAutoCommit()) { + poolalbeConnection.setAutoCommit(false); + } + + return poolalbeConnection; + } + } + + /** + * 抛弃连接,不进行回收,而是抛弃 + * + * @param realConnection + * @throws SQLException + */ + public void discardConnection(Connection realConnection) { + JdbcUtils.close(realConnection); + + try { + lock.lockInterruptibly(); + } catch (InterruptedException e) { + LOG.error("interrupt"); + return; + } + try { + activeCount--; + discardCount++; + + if (activeCount <= 0) { + empty.signal(); + } + } finally { + lock.unlock(); + } + } + + private DruidPooledConnection getConnectionInternal(long maxWait) throws SQLException { + if (closed) { + connectErrorCount.incrementAndGet(); + throw new DataSourceClosedException("dataSource already closed at " + new Date(closeTimeMillis)); + } + + if (!enable) { + connectErrorCount.incrementAndGet(); + throw new DataSourceDisableException(); + } + + final long nanos = TimeUnit.MILLISECONDS.toNanos(maxWait); + final int maxWaitThreadCount = getMaxWaitThreadCount(); + + DruidConnectionHolder holder; + try { + lock.lockInterruptibly(); + } catch (InterruptedException e) { + connectErrorCount.incrementAndGet(); + throw new SQLException("interrupt", e); + } + + try { + if (maxWaitThreadCount > 0) { + if (notEmptyWaitThreadCount >= maxWaitThreadCount) { + connectErrorCount.incrementAndGet(); + throw new SQLException("maxWaitThreadCount " + maxWaitThreadCount + ", current wait Thread count " + + lock.getQueueLength()); + } + } + + connectCount++; + + if (maxWait > 0) { + holder = pollLast(nanos); + } else { + holder = takeLast(); + } + + activeCount++; + if (activeCount > activePeak) { + activePeak = activeCount; + activePeakTime = System.currentTimeMillis(); + } + + } catch (InterruptedException e) { + connectErrorCount.incrementAndGet(); + throw new SQLException(e.getMessage(), e); + } catch (SQLException e) { + connectErrorCount.incrementAndGet(); + throw e; + } finally { + lock.unlock(); + } + + holder.incrementUseCount(); + + DruidPooledConnection poolalbeConnection = new DruidPooledConnection(holder); + return poolalbeConnection; + } + + public void handleConnectionException(DruidPooledConnection pooledConnection, Throwable t) throws SQLException { + final DruidConnectionHolder holder = pooledConnection.getConnectionHolder(); + + errorCount.incrementAndGet(); + lastError = t; + lastErrorTimeMillis = System.currentTimeMillis(); + + if (t instanceof SQLException) { + SQLException sqlEx = (SQLException) t; + + // broadcastConnectionError + ConnectionEvent event = new ConnectionEvent(pooledConnection, sqlEx); + for (ConnectionEventListener eventListener : holder.getConnectionEventListeners()) { + eventListener.connectionErrorOccurred(event); + } + + // exceptionSorter.isExceptionFatal + if (exceptionSorter != null && exceptionSorter.isExceptionFatal(sqlEx)) { + if (pooledConnection.isTraceEnable()) { + synchronized (activeConnections) { + if (pooledConnection.isTraceEnable()) { + activeConnections.remove(pooledConnection); + pooledConnection.setTraceEnable(false); + } + } + } + this.discardConnection(holder.getConnection()); + holder.setDiscard(true); + pooledConnection.disable(t); + } + + throw sqlEx; + } else { + throw new SQLException("Error", t); + } + } + + /** + * 回收连接 + */ + protected void recycle(DruidPooledConnection pooledConnection) throws SQLException { + final DruidConnectionHolder holder = pooledConnection.getConnectionHolder(); + + if (holder == null) { + LOG.warn("connectionHolder is null"); + return; + } + + if (pooledConnection.getOwnerThread() != Thread.currentThread()) { + LOG.warn("get/close not same thread"); + } + + final Connection physicalConnection = holder.getConnection(); + + if (pooledConnection.isTraceEnable()) { + synchronized (activeConnections) { + if (pooledConnection.isTraceEnable()) { + Object oldInfo = activeConnections.remove(pooledConnection); + if (oldInfo == null) { + if (LOG.isWarnEnabled()) { + LOG.warn("remove abandonded failed. activeConnections.size " + activeConnections.size()); + } + } + pooledConnection.setTraceEnable(false); + } + } + } + + final boolean isAutoCommit = holder.isUnderlyingAutoCommit(); + final boolean isReadOnly = holder.isUnderlyingReadOnly(); + final boolean testOnReturn = this.isTestOnReturn(); + + try { + // check need to rollback? + if ((!isAutoCommit) && (!isReadOnly)) { + pooledConnection.rollback(); + } + + // reset holder, restore default settings, clear warnings + holder.reset(); + + if (testOnReturn) { + boolean validate = testConnectionInternal(physicalConnection); + if (!validate) { + JdbcUtils.close(physicalConnection); + + destroyCount.incrementAndGet(); + + lock.lockInterruptibly(); + try { + activeCount--; + closeCount++; + } finally { + lock.unlock(); + } + return; + } + } + + if (!enable) { + discardConnection(holder.getConnection()); + return; + } + + final long lastActiveTimeMillis = System.currentTimeMillis(); + lock.lockInterruptibly(); + try { + activeCount--; + closeCount++; + + putLast(holder, lastActiveTimeMillis); + recycleCount++; + } finally { + lock.unlock(); + } + } catch (Throwable e) { + holder.clearStatementCache(); + + if (!holder.isDiscard()) { + this.discardConnection(physicalConnection); + holder.setDiscard(true); + } + + LOG.error("recyle error", e); + recycleErrorCount.incrementAndGet(); + } + } + + public long getRecycleErrorCount() { + return recycleErrorCount.get(); + } + + public void clearStatementCache() throws SQLException { + lock.lock(); + try { + for (int i = 0; i < poolingCount; ++i) { + DruidConnectionHolder conn = connections[i]; + conn.getStatementPool().clear(); + } + } finally { + lock.unlock(); + } + } + + /** + * close datasource + */ + public void close() { + lock.lock(); + try { + if (this.closed) { + return; + } + + if (!this.inited) { + return; + } + + if (logStatsThread != null) { + logStatsThread.interrupt(); + } + + if (createConnectionThread != null) { + createConnectionThread.interrupt(); + } + + if (destoryConnectionThread != null) { + destoryConnectionThread.interrupt(); + } + + for (int i = 0; i < poolingCount; ++i) { + try { + DruidConnectionHolder connHolder = connections[i]; + + for (PreparedStatementHolder stmtHolder : connHolder.getStatementPool().getMap().values()) { + connHolder.getStatementPool().closeRemovedStatement(stmtHolder); + } + connHolder.getStatementPool().getMap().clear(); + + Connection physicalConnection = connHolder.getConnection(); + physicalConnection.close(); + connections[i] = null; + destroyCount.incrementAndGet(); + } catch (Exception ex) { + LOG.warn("close connection error", ex); + } + } + poolingCount = 0; + DruidDataSourceStatManager.removeDataSource(this); + + enable = false; + notEmpty.signalAll(); + notEmptySignalCount++; + + this.closed = true; + this.closeTimeMillis = System.currentTimeMillis(); + + for (Filter filter : filters) { + filter.destory(); + } + } finally { + lock.unlock(); + } + + if (LOG.isInfoEnabled()) { + LOG.info("{dataSource-" + this.getID() + "} closed"); + } + } + + void putLast(DruidConnectionHolder e, long lastActiveTimeMillis) { + e.setLastActiveTimeMillis(lastActiveTimeMillis); + connections[poolingCount++] = e; + + if (poolingCount > poolingPeak) { + poolingPeak = poolingCount; + poolingPeakTime = lastActiveTimeMillis; + } + + notEmpty.signal(); + notEmptySignalCount++; + } + + DruidConnectionHolder takeLast() throws InterruptedException, SQLException { + try { + while (poolingCount == 0) { + empty.signal(); // send signal to CreateThread create connection + notEmptyWaitThreadCount++; + if (notEmptyWaitThreadCount > notEmptyWaitThreadPeak) { + notEmptyWaitThreadPeak = notEmptyWaitThreadCount; + } + try { + notEmpty.await(); // signal by recycle or creator + } finally { + notEmptyWaitThreadCount--; + } + notEmptyWaitCount++; + + if (!enable) { + connectErrorCount.incrementAndGet(); + throw new DataSourceDisableException(); + } + } + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + notEmptySignalCount++; + throw ie; + } + + poolingCount--; + DruidConnectionHolder last = connections[poolingCount]; + connections[poolingCount] = null; + + return last; + } + + DruidConnectionHolder pollLast(long nanos) throws InterruptedException, SQLException { + long estimate = nanos; + + for (int i = 0;; ++i) { + if (poolingCount == 0) { + empty.signal(); // send signal to CreateThread create connection + + if (estimate <= 0) { + if (this.createError == null) { + throw new GetConnectionTimeoutException(createError); + } else { + throw new GetConnectionTimeoutException(); + } + } + + notEmptyWaitThreadCount++; + if (notEmptyWaitThreadCount > notEmptyWaitThreadPeak) { + notEmptyWaitThreadPeak = notEmptyWaitThreadCount; + } + + try { + long startEstimate = estimate; + estimate = notEmpty.awaitNanos(estimate); // signal by + // recycle or + // creator + notEmptyWaitCount++; + notEmptyWaitNanos += (startEstimate - estimate); + + if (!enable) { + connectErrorCount.incrementAndGet(); + throw new DataSourceDisableException(); + } + } catch (InterruptedException ie) { + notEmpty.signal(); // propagate to non-interrupted thread + notEmptySignalCount++; + throw ie; + } finally { + notEmptyWaitThreadCount--; + } + + if (poolingCount == 0) { + if (estimate > 0) { + continue; + } + + if (createError != null) { + throw new GetConnectionTimeoutException(createError); + } else { + throw new GetConnectionTimeoutException("loopWaitCount " + i + ", wait millis " + + (nanos - estimate) / (1000 * 1000)); + } + } + } + + poolingCount--; + DruidConnectionHolder last = connections[poolingCount]; + connections[poolingCount] = null; + + return last; + } + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + if (!StringUtils.equals(username, this.username)) { + throw new UnsupportedOperationException("Not supported by DruidDataSource"); + } + + if (!StringUtils.equals(password, this.password)) { + throw new UnsupportedOperationException("Not supported by DruidDataSource"); + } + + return getConnection(); + } + + public long getCreateCount() { + return createCount.get(); + } + + public long getDestroyCount() { + return destroyCount.get(); + } + + public long getConnectCount() { + lock.lock(); + try { + return connectCount; + } finally { + lock.unlock(); + } + } + + public long getCloseCount() { + return closeCount; + } + + public long getConnectErrorCount() { + return connectErrorCount.get(); + } + + @Override + public int getPoolingCount() { + lock.lock(); + try { + return poolingCount; + } finally { + lock.unlock(); + } + } + + public int getPoolingPeak() { + lock.lock(); + try { + return poolingPeak; + } finally { + lock.unlock(); + } + } + + public Date getPoolingPeakTime() { + if (poolingPeakTime <= 0) { + return null; + } + + return new Date(poolingPeakTime); + } + + public long getRecycleCount() { + return recycleCount; + } + + public int getActiveCount() { + lock.lock(); + try { + return activeCount; + } finally { + lock.unlock(); + } + } + + public void logStats() { + final DruidDataSourceStatLogger statLogger = this.statLogger; + if (statLogger == null) { + return; + } + + DruidDataSourceStatValue statValue = getStatValueAndReset(); + + statLogger.log(statValue); + } + + public DruidDataSourceStatValue getStatValueAndReset() { + DruidDataSourceStatValue value = new DruidDataSourceStatValue(); + + lock.lock(); + try { + value.poolingCount = this.poolingCount; + value.poolingPeak = this.poolingPeak; + value.poolingPeakTime = this.poolingPeakTime; + + value.activeCount = this.activeCount; + value.activePeak = this.activePeak; + value.activePeakTime = this.activePeakTime; + + value.connectCount = this.connectCount; + value.closeCount = this.closeCount; + value.waitThreadCount = lock.getWaitQueueLength(notEmpty); + value.notEmptyWaitCount = this.notEmptyWaitCount; + value.notEmptyWaitNanos = this.notEmptyWaitNanos; + + // reset + this.poolingPeak = 0; + this.poolingPeakTime = 0; + this.activePeak = 0; + this.activePeakTime = 0; + this.connectCount = 0; + this.closeCount = 0; + + this.notEmptyWaitCount = 0; + this.notEmptyWaitNanos = 0; + } finally { + lock.unlock(); + } + + value.name = this.getName(); + value.dbType = this.getDbType(); + value.driverClassName = this.getDriverClassName(); + + value.url = this.getUrl(); + value.userName = this.getUsername(); + value.filterClassNames = this.getFilterClassNames(); + + value.initialSize = this.getInitialSize(); + value.minIdle = this.getMinIdle(); + value.maxActive = this.getMaxActive(); + + value.queryTimeout = this.getQueryTimeout(); + value.transactionQueryTimeout = this.getTransactionQueryTimeout(); + value.loginTimeout = this.getLoginTimeout(); + value.validConnectionCheckerClassName = this.getValidConnectionCheckerClassName(); + value.exceptionSorterClassName = this.getExceptionSorterClassName(); + + value.testOnBorrow = this.isTestOnBorrow(); + value.testOnReturn = this.isTestOnReturn(); + value.testWhileIdle = this.isTestWhileIdle(); + + value.defaultAutoCommit = this.isDefaultAutoCommit(); + value.defaultReadOnly = this.isDefaultAutoCommit(); + value.defaultTransactionIsolation = this.getDefaultTransactionIsolation(); + + value.logicConnectErrorCount = connectErrorCount.getAndSet(0); + + value.physicalConnectCount = createCount.getAndSet(0); + value.physicalCloseCount = destroyCount.getAndSet(0); + value.physicalConnectErrorCount = createErrorCount.getAndSet(0); + + value.executeCount = this.executeCount.getAndSet(0); + value.errorCount = errorCount.getAndSet(0); + value.commitCount = commitCount.getAndSet(0); + value.rollbackCount = rollbackCount.getAndSet(0); + + value.pstmtCacheHitCount = cachedPreparedStatementHitCount.getAndSet(0); + value.pstmtCacheMissCount = cachedPreparedStatementMissCount.getAndSet(0); + + value.startTransactionCount = startTransactionCount.getAndSet(0); + value.transactionHistogram = this.getTransactionHistogram().toArrayAndReset(); + + value.connectionHoldTimeHistogram = this.getDataSourceStat().getConnectionHoldHistogram().toArrayAndReset(); + value.removeAbandoned = this.isRemoveAbandoned(); + value.clobOpenCount = this.getDataSourceStat().getClobOpenCountAndReset(); + value.blobOpenCount = this.getDataSourceStat().getBlobOpenCountAndReset(); + + value.sqlSkipCount = this.getDataSourceStat().getSkipSqlCountAndReset(); + value.sqlList = this.getDataSourceStat().getSqlStatMapAndReset(); + + return value; + } + + public long getRemoveAbandonedCount() { + return removeAbandonedCount; + } + + public class CreateConnectionThread extends Thread { + + public CreateConnectionThread(String name){ + super(name); + this.setDaemon(true); + } + + public void run() { + initedLatch.countDown(); + + int errorCount = 0; + for (;;) { + // addLast + try { + lock.lockInterruptibly(); + } catch (InterruptedException e2) { + break; + } + + try { + // 必须存在线程等待,才创建连接 + if (poolingCount >= notEmptyWaitThreadCount) { + empty.await(); + } + + // 防止创建超过maxActive数量的连接 + if (activeCount + poolingCount >= maxActive) { + empty.await(); + continue; + } + + } catch (InterruptedException e) { + lastCreateError = e; + lastErrorTimeMillis = System.currentTimeMillis(); + break; + } finally { + lock.unlock(); + } + + Connection connection = null; + + try { + connection = createPhysicalConnection(); + } catch (SQLException e) { + LOG.error("create connection error", e); + + errorCount++; + + if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) { + if (breakAfterAcquireFailure) { + break; + } + + try { + Thread.sleep(timeBetweenConnectErrorMillis); + } catch (InterruptedException interruptEx) { + break; + } + } + } catch (RuntimeException e) { + LOG.error("create connection error", e); + continue; + } catch (Error e) { + LOG.error("create connection error", e); + break; + } + + if (connection == null) { + continue; + } + + DruidConnectionHolder holder = null; + try { + holder = new DruidConnectionHolder(DruidDataSource.this, connection); + } catch (SQLException ex) { + LOG.error("create connection holder error", ex); + break; + } + + lock.lock(); + try { + connections[poolingCount++] = holder; + + if (poolingCount > poolingPeak) { + poolingPeak = poolingCount; + poolingPeakTime = System.currentTimeMillis(); + } + + errorCount = 0; // reset errorCount + + notEmpty.signal(); + notEmptySignalCount++; + } finally { + lock.unlock(); + } + } + } + } + + public class DestroyConnectionThread extends Thread { + + public DestroyConnectionThread(String name){ + super(name); + this.setDaemon(true); + } + + public void run() { + initedLatch.countDown(); + + for (;;) { + // 从前面开始删除 + try { + if (closed) { + break; + } + + if (timeBetweenEvictionRunsMillis > 0) { + Thread.sleep(timeBetweenEvictionRunsMillis); + } else { + Thread.sleep(1000); // + } + + if (Thread.interrupted()) { + break; + } + + shrink(true); + + if (isRemoveAbandoned()) { + removeAbandoned(); + } + } catch (InterruptedException e) { + break; + } + } + } + + } + + public class LogStatsThread extends Thread { + + public LogStatsThread(String name){ + super(name); + this.setDaemon(true); + } + + public void run() { + try { + for (;;) { + try { + logStats(); + } catch (Exception e) { + LOG.error("logStats error", e); + } + + Thread.sleep(timeBetweenLogStatsMillis); + } + } catch (InterruptedException e) { + // skip + } + } + } + + public int removeAbandoned() { + int removeCount = 0; + + long currrentNanos = System.nanoTime(); + + List abandonedList = new ArrayList(); + + synchronized (activeConnections) { + Iterator iter = activeConnections.keySet().iterator(); + + for (; iter.hasNext();) { + DruidPooledConnection pooledConnection = iter.next(); + + if (pooledConnection.isRunning()) { + continue; + } + + long timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (1000 * 1000); + + if (timeMillis >= removeAbandonedTimeoutMillis) { + iter.remove(); + pooledConnection.setTraceEnable(false); + abandonedList.add(pooledConnection); + } + } + } + + if (abandonedList.size() > 0) { + for (DruidPooledConnection pooledConnection : abandonedList) { + JdbcUtils.close(pooledConnection); + pooledConnection.abandond(); + removeAbandonedCount++; + removeCount++; + + if (isLogAbandoned()) { + StringBuilder buf = new StringBuilder(); + buf.append("abandon connection, open stackTrace\n"); + + StackTraceElement[] trace = pooledConnection.getConnectStackTrace(); + for (int i = 0; i < trace.length; i++) { + buf.append("\tat "); + buf.append(trace[i].toString()); + buf.append("\n"); + } + + LOG.error(buf.toString()); + } + } + } + + return removeCount; + } + + /** Instance key */ + protected String instanceKey = null; + + public Reference getReference() throws NamingException { + final String className = getClass().getName(); + final String factoryName = className + "Factory"; // XXX: not robust + Reference ref = new Reference(className, factoryName, null); + ref.add(new StringRefAddr("instanceKey", instanceKey)); + ref.add(new StringRefAddr("url", this.getUrl())); + ref.add(new StringRefAddr("username", this.getUsername())); + ref.add(new StringRefAddr("password", this.getPassword())); + // TODO ADD OTHER PROPERTIES + return ref; + } + + @Override + public List getFilterClassNames() { + List names = new ArrayList(); + for (Filter filter : filters) { + names.add(filter.getClass().getName()); + } + return names; + } + + public int getRawDriverMajorVersion() { + int version = -1; + if (this.driver != null) { + version = driver.getMajorVersion(); + } + return version; + } + + public int getRawDriverMinorVersion() { + int version = -1; + if (this.driver != null) { + version = driver.getMinorVersion(); + } + return version; + } + + public String getProperties() { + Properties properties = new Properties(); + properties.putAll(connectProperties); + if (properties.containsKey("password")) { + properties.put("password", "******"); + } + return properties.toString(); + } + + @Override + public void shrink() { + shrink(false); + } + + public void shrink(boolean checkTime) { + final List evictList = new ArrayList(); + try { + lock.lockInterruptibly(); + } catch (InterruptedException e) { + return; + } + + try { + final int checkCount = poolingCount - minIdle; + for (int i = 0; i < checkCount; ++i) { + DruidConnectionHolder connection = connections[i]; + + if (checkTime) { + long idleMillis = System.currentTimeMillis() - connection.getLastActiveTimeMillis(); + if (idleMillis >= minEvictableIdleTimeMillis) { + evictList.add(connection); + } else { + break; + } + } else { + evictList.add(connection); + } + } + + int removeCount = evictList.size(); + if (removeCount > 0) { + System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount); + Arrays.fill(connections, poolingCount - removeCount, poolingCount, null); + poolingCount -= removeCount; + } + } finally { + lock.unlock(); + } + + for (DruidConnectionHolder item : evictList) { + Connection connection = item.getConnection(); + JdbcUtils.close(connection); + destroyCount.incrementAndGet(); + } + } + + public int getWaitThreadCount() { + lock.lock(); + try { + return lock.getWaitQueueLength(notEmpty); + } finally { + lock.unlock(); + } + } + + public long getNotEmptyWaitCount() { + return notEmptyWaitCount; + } + + public int getNotEmptyWaitThreadCount() { + lock.lock(); + try { + return notEmptyWaitThreadCount; + } finally { + lock.unlock(); + } + } + + public int getNotEmptyWaitThreadPeak() { + lock.lock(); + try { + return notEmptyWaitThreadPeak; + } finally { + lock.unlock(); + } + } + + public long getNotEmptySignalCount() { + return notEmptySignalCount; + } + + public long getNotEmptyWaitMillis() { + return notEmptyWaitNanos / (1000 * 1000); + } + + public long getNotEmptyWaitNanos() { + return notEmptyWaitNanos; + } + + public int getLockQueueLength() { + return lock.getQueueLength(); + } + + public int getActivePeak() { + return activePeak; + } + + public Date getActivePeakTime() { + if (activePeakTime <= 0) { + return null; + } + + return new Date(activePeakTime); + } + + public String dump() { + lock.lock(); + try { + return this.toString(); + } finally { + lock.unlock(); + } + } + + public long getErrorCount() { + return this.errorCount.get(); + } + + public String toString() { + StringBuilder buf = new StringBuilder(); + + buf.append("{"); + + buf.append("\n\tCreateTime:\""); + buf.append(IOUtils.toString(getCreatedTime())); + buf.append("\""); + + buf.append(",\n\tActiveCount:"); + buf.append(getActiveCount()); + + buf.append(",\n\tPoolingCount:"); + buf.append(getPoolingCount()); + + buf.append(",\n\tCreateCount:"); + buf.append(getCreateCount()); + + buf.append(",\n\tDestroyCount:"); + buf.append(getDestroyCount()); + + buf.append(",\n\tCloseCount:"); + buf.append(getCloseCount()); + + buf.append(",\n\tConnectCount:"); + buf.append(getConnectCount()); + + buf.append(",\n\tConnections:["); + for (int i = 0; i < poolingCount; ++i) { + DruidConnectionHolder conn = connections[i]; + if (conn != null) { + if (i != 0) { + buf.append(","); + } + buf.append("\n\t\t"); + buf.append(conn.toString()); + } + } + buf.append("\n\t]"); + + buf.append("\n}"); + + if (this.isPoolPreparedStatements()) { + buf.append("\n\n["); + for (int i = 0; i < poolingCount; ++i) { + DruidConnectionHolder conn = connections[i]; + if (conn != null) { + if (i != 0) { + buf.append(","); + } + buf.append("\n\t{\n\tID:"); + buf.append(System.identityHashCode(conn.getConnection())); + PreparedStatementPool pool = conn.getStatementPool(); + + buf.append(", \n\tpoolStatements:["); + + int entryIndex = 0; + try { + for (Map.Entry entry : pool.getMap().entrySet()) { + if (entryIndex != 0) { + buf.append(","); + } + buf.append("\n\t\t{hitCount:"); + buf.append(entry.getValue().getHitCount()); + buf.append(",sql:\""); + buf.append(entry.getKey().getSql()); + buf.append("\""); + buf.append("\t}"); + + entryIndex++; + } + } catch (ConcurrentModificationException e) { + // skip .. + } + + buf.append("\n\t\t]"); + + buf.append("\n\t}"); + } + } + buf.append("\n]"); + } + + return buf.toString(); + } + + public List> getPoolingConnectionInfo() { + List> list = new ArrayList>(); + lock.lock(); + try { + for (int i = 0; i < poolingCount; ++i) { + DruidConnectionHolder connHolder = connections[i]; + Connection conn = connHolder.getConnection(); + + Map map = new LinkedHashMap(); + map.put("id", System.identityHashCode(conn)); + map.put("useCount", connHolder.getUseCount()); + if (connHolder.getLastActiveTimeMillis() > 0) { + map.put("lastActiveTime", new Date(connHolder.getLastActiveTimeMillis())); + } + map.put("connectTime", new Date(connHolder.getTimeMillis())); + map.put("holdability", connHolder.getUnderlyingHoldability()); + map.put("transactionIsolation", connHolder.getUnderlyingTransactionIsolation()); + map.put("autoCommit", connHolder.isUnderlyingAutoCommit()); + map.put("readoOnly", connHolder.isUnderlyingReadOnly()); + + if (connHolder.isPoolPreparedStatements()) { + List> stmtCache = new ArrayList>(); + PreparedStatementPool stmtPool = connHolder.getStatementPool(); + for (PreparedStatementHolder stmtHolder : stmtPool.getMap().values()) { + Map stmtInfo = new LinkedHashMap(); + + stmtInfo.put("sql", stmtHolder.getKey().getSql()); + stmtInfo.put("defaultRowPretch", stmtHolder.getDefaultRowPretch()); + stmtInfo.put("rowPrefetch", stmtHolder.getRowPrefetch()); + stmtInfo.put("hitCount", stmtHolder.getHitCount()); + + stmtCache.add(stmtInfo); + } + + map.put("pscache", stmtCache); + } + + list.add(map); + } + } finally { + lock.unlock(); + } + return list; + } + + public void logTransaction(TransactionInfo info) { + long transactionMillis = info.getEndTimeMillis() - info.getStartTimeMillis(); + if (transactionThresholdMillis > 0 && transactionMillis > transactionThresholdMillis) { + StringBuilder buf = new StringBuilder(); + buf.append("long time transaction, take "); + buf.append(transactionMillis); + buf.append(" ms : "); + for (String sql : info.getSqlList()) { + buf.append(sql); + buf.append(";"); + } + LOG.error(buf.toString(), new TransactionTimeoutException()); + } + } + + @Override + public String getVersion() { + return VERSION.getVersionNumber(); + } + + @Override + public JdbcDataSourceStat getDataSourceStat() { + return dataSourceStat; + } + + public Object clone() throws CloneNotSupportedException { + return cloneDruidDataSource(); + } + + public DruidDataSource cloneDruidDataSource() { + DruidDataSource x = new DruidDataSource(); + + cloneTo(x); + + return x; + } + + public Map getStatDataForMBean() { + try { + Map map = new HashMap(); + + // 0 - 4 + map.put("Name", this.getName()); + map.put("URL", this.getUrl()); + map.put("CreateCount", this.getCreateCount()); + map.put("DestroyCount", this.getDestroyCount()); + map.put("ConnectCount", this.getConnectCount()); + + // 5 - 9 + map.put("CloseCount", this.getCloseCount()); + map.put("ActiveCount", this.getActivePeak()); + map.put("PoolingCount", this.getPoolingCount()); + map.put("LockQueueLength", this.getLockQueueLength()); + map.put("WaitThreadCount", this.getNotEmptyWaitThreadPeak()); + + // 10 - 14 + map.put("InitialSize", this.getInitialSize()); + map.put("MaxActive", this.getMaxActive()); + map.put("MinIdle", this.getMinIdle()); + map.put("PoolPreparedStatements", this.isPoolPreparedStatements()); + map.put("TestOnBorrow", this.isTestOnBorrow()); + + // 15 - 19 + map.put("TestOnReturn", this.isTestOnReturn()); + map.put("MinEvictableIdleTimeMillis", this.getMinEvictableIdleTimeMillis()); + map.put("ConnectErrorCount", this.getConnectErrorCount()); + map.put("CreateTimespanMillis", this.getCreateTimespanMillis()); + map.put("DbType", this.getDbType()); + + // 20 - 24 + map.put("ValidationQuery", this.getValidationQuery()); + map.put("ValidationQueryTimeout", this.getValidationQueryTimeout()); + map.put("DriverClassName", this.getDriverClassName()); + map.put("Username", this.getUsername()); + map.put("RemoveAbandonedCount", this.getRemoveAbandonedCount()); + + // 25 - 29 + map.put("NotEmptyWaitCount", this.getNotEmptyWaitCount()); + map.put("NotEmptyWaitNanos", this.getNotEmptyWaitNanos()); + map.put("ErrorCount", this.getErrorCount()); + map.put("ReusePreparedStatementCount", this.getCachedPreparedStatementHitCount()); + map.put("StartTransactionCount", this.getStartTransactionCount()); + + // 30 - 34 + map.put("CommitCount", this.getCommitCount()); + map.put("RollbackCount", this.getRollbackCount()); + map.put("LastError", JMXUtils.getErrorCompositeData(this.getLastError())); + map.put("LastCreateError", JMXUtils.getErrorCompositeData(this.getLastCreateError())); + map.put("PreparedStatementCacheDeleteCount", this.getCachedPreparedStatementDeleteCount()); + + // 35 - 39 + map.put("PreparedStatementCacheAccessCount", this.getCachedPreparedStatementAccessCount()); + map.put("PreparedStatementCacheMissCount", this.getCachedPreparedStatementMissCount()); + map.put("PreparedStatementCacheHitCount", this.getCachedPreparedStatementHitCount()); + map.put("PreparedStatementCacheCurrentCount", this.getCachedPreparedStatementCount()); + map.put("Version", this.getVersion()); + + // 40 - + map.put("LastErrorTime", this.getLastErrorTime()); + map.put("LastCreateErrorTime", this.getLastCreateErrorTime()); + map.put("CreateErrorCount", this.getCreateErrorCount()); + map.put("DiscardCount", this.getDiscardCount()); + + return map; + } catch (JMException ex) { + throw new IllegalStateException("getStatData error", ex); + } + } + + public Map getStatData() { + final int activeCount; + final int activePeak; + final Date activePeakTime; + + final int poolingCount; + final int poolingPeak; + final Date poolingPeakTime; + + final long connectCount; + final long closeCount; + + lock.lock(); + try { + poolingCount = this.poolingCount; + poolingPeak = this.poolingPeak; + poolingPeakTime = this.getPoolingPeakTime(); + + activeCount = this.activeCount; + activePeak = this.activePeak; + activePeakTime = this.getActivePeakTime(); + + connectCount = this.connectCount; + closeCount = this.closeCount; + } finally { + lock.unlock(); + } + Map dataMap = new LinkedHashMap(); + + dataMap.put("Identity", System.identityHashCode(this)); + dataMap.put("Name", this.getName()); + dataMap.put("DbType", this.getDbType()); + dataMap.put("DriverClassName", this.getDriverClassName()); + + dataMap.put("URL", this.getUrl()); + dataMap.put("UserName", this.getUsername()); + dataMap.put("FilterClassNames", this.getFilterClassNames()); + + dataMap.put("WaitThreadCount", this.getWaitThreadCount()); + dataMap.put("NotEmptyWaitCount", this.getNotEmptyWaitCount()); + dataMap.put("NotEmptyWaitMillis", this.getNotEmptyWaitMillis()); + + dataMap.put("PoolingCount", poolingCount); + dataMap.put("PoolingPeak", poolingPeak); + dataMap.put("PoolingPeakTime", poolingPeakTime); + + dataMap.put("ActiveCount", activeCount); + dataMap.put("ActivePeak", activePeak); + dataMap.put("ActivePeakTime", activePeakTime); + + dataMap.put("InitialSize", this.getInitialSize()); + dataMap.put("MinIdle", this.getMinIdle()); + dataMap.put("MaxActive", this.getMaxActive()); + + dataMap.put("QueryTimeout", this.getQueryTimeout()); + dataMap.put("TransactionQueryTimeout", this.getTransactionQueryTimeout()); + dataMap.put("LoginTimeout", this.getLoginTimeout()); + dataMap.put("ValidConnectionCheckerClassName", this.getValidConnectionCheckerClassName()); + dataMap.put("ExceptionSorterClassName", this.getExceptionSorterClassName()); + + dataMap.put("TestOnBorrow", this.isTestOnBorrow()); + dataMap.put("TestOnReturn", this.isTestOnReturn()); + dataMap.put("TestWhileIdle", this.isTestWhileIdle()); + + dataMap.put("DefaultAutoCommit", this.isDefaultAutoCommit()); + dataMap.put("DefaultReadOnly", this.isDefaultAutoCommit()); + dataMap.put("DefaultTransactionIsolation", this.getDefaultTransactionIsolation()); + + dataMap.put("LogicConnectCount", connectCount); + dataMap.put("LogicCloseCount", closeCount); + dataMap.put("LogicConnectErrorCount", this.getConnectErrorCount()); + + dataMap.put("PhysicalConnectCount", this.getCreateCount()); + dataMap.put("PhysicalCloseCount", this.getDestroyCount()); + dataMap.put("PhysicalConnectErrorCount", this.getCreateErrorCount()); + + dataMap.put("ExecuteCount", this.getExecuteCount()); + dataMap.put("ErrorCount", this.getErrorCount()); + dataMap.put("CommitCount", this.getCommitCount()); + dataMap.put("RollbackCount", this.getRollbackCount()); + + dataMap.put("PSCacheAccessCount", this.getCachedPreparedStatementAccessCount()); + dataMap.put("PSCacheHitCount", this.getCachedPreparedStatementHitCount()); + dataMap.put("PSCacheMissCount", this.getCachedPreparedStatementMissCount()); + + dataMap.put("StartTransactionCount", this.getStartTransactionCount()); + dataMap.put("TransactionHistogram", this.getTransactionHistogramValues()); + + dataMap.put("ConnectionHoldTimeHistogram", this.getDataSourceStat().getConnectionHoldHistogram().toArray()); + dataMap.put("RemoveAbandoned", this.isRemoveAbandoned()); + dataMap.put("ClobOpenCount", this.getDataSourceStat().getClobOpenCount()); + dataMap.put("BlobOpenCount", this.getDataSourceStat().getBlobOpenCount()); + + return dataMap; + } + + public JdbcSqlStat getSqlStat(int sqlId) { + return this.getDataSourceStat().getSqlStat(sqlId); + } + + public JdbcSqlStat getSqlStat(long sqlId) { + return this.getDataSourceStat().getSqlStat(sqlId); + } + + public Map getSqlStatMap() { + return this.getDataSourceStat().getSqlStatMap(); + } + + public Map getWallStatMap() { + for (Filter filter : this.filters) { + if (filter instanceof WallFilter) { + WallFilter wallFilter = (WallFilter) filter; + return wallFilter.getProvider().getStatsMap(); + } + } + + return null; + } + + public Lock getLock() { + return lock; + } + + @Override + public boolean isWrapperFor(Class iface) { + for (Filter filter : this.filters) { + if (filter.isWrapperFor(iface)) { + return true; + } + } + + if (this.statLogger != null + && (this.statLogger.getClass() == iface || DruidDataSourceStatLogger.class == iface)) { + return true; + } + + return super.isWrapperFor(iface); + } + + @SuppressWarnings("unchecked") + public T unwrap(Class iface) { + for (Filter filter : this.filters) { + if (filter.isWrapperFor(iface)) { + return (T) filter; + } + } + + if (this.statLogger != null + && (this.statLogger.getClass() == iface || DruidDataSourceStatLogger.class == iface)) { + return (T) statLogger; + } + + return super.unwrap(iface); + } +} diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerAdapter.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerAdapter.java index 1caeceb131..76df534148 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerAdapter.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerAdapter.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2011 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.util.Properties; diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java index 755c0baa26..4622fc19ee 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSourceStatLoggerImpl.java @@ -33,7 +33,9 @@ import com.alibaba.druid.support.logging.LogFactory; */ public class DruidDataSourceStatLoggerImpl extends DruidDataSourceStatLoggerAdapter { - private static Log LOG = LogFactory.getLog(DruidDataSourceStatLoggerImpl.class); + private static Log LOG = LogFactory.getLog(DruidDataSourceStatLoggerImpl.class); + + private Log logger = LOG; public DruidDataSourceStatLoggerImpl(){ this.configFromProperties(System.getProperties()); @@ -44,12 +46,23 @@ public class DruidDataSourceStatLoggerImpl extends DruidDataSourceStatLoggerAdap */ @Override public void configFromProperties(Properties properties) { + String property = properties.getProperty("druid.stat.loggerName"); + if (property != null && property.length() > 0) { + setLoggerName(property); + } + } + + public Log getLogger() { + return logger; + } + public void setLoggerName(String loggerName) { + logger = LogFactory.getLog(loggerName); } @Override public void log(DruidDataSourceStatValue statValue) { - if (LOG.isInfoEnabled()) { + if (logger.isInfoEnabled()) { Map map = new LinkedHashMap(); map.put("url", statValue.url); @@ -205,7 +218,7 @@ public class DruidDataSourceStatLoggerImpl extends DruidDataSourceStatLoggerAdap String text = JSONUtils.toJSONString(map); - LOG.info(text); + logger.info(text); } } diff --git a/src/main/java/com/alibaba/druid/pool/ValidConnectionCheckerAdapter.java b/src/main/java/com/alibaba/druid/pool/ValidConnectionCheckerAdapter.java index 218b0ca686..96e669a215 100644 --- a/src/main/java/com/alibaba/druid/pool/ValidConnectionCheckerAdapter.java +++ b/src/main/java/com/alibaba/druid/pool/ValidConnectionCheckerAdapter.java @@ -1,3 +1,18 @@ +/* + * Copyright 1999-2011 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; diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java index 0b9f84fcd6..dce42ce5b3 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLCastExpr.java @@ -36,6 +36,9 @@ public class SQLCastExpr extends SQLExprImpl { } public void setExpr(SQLExpr expr) { + if (expr != null) { + expr.setParent(this); + } this.expr = expr; } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java index 45642ca86d..fdfd160a46 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java @@ -796,6 +796,10 @@ public class SQLEvalVisitorUtils { if (wallConditionContext != null) { wallConditionContext.setConstArithmetic(true); } + + if (leftValue == null || rightValue == null) { + return false; + } Object value = null; switch (x.getOperator()) { diff --git a/src/main/java/com/alibaba/druid/sql/visitor/functions/Concat.java b/src/main/java/com/alibaba/druid/sql/visitor/functions/Concat.java index 57aa04f7e7..43a805b216 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/functions/Concat.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/functions/Concat.java @@ -33,7 +33,7 @@ public class Concat implements Function { Object itemValue = item.getAttributes().get(EVAL_VALUE); if (itemValue == null) { - continue; + return null; } buf.append(itemValue.toString()); } diff --git a/src/main/java/com/alibaba/druid/support/logging/JakartaCommonsLoggingImpl.java b/src/main/java/com/alibaba/druid/support/logging/JakartaCommonsLoggingImpl.java index b66225b71b..70203bce41 100644 --- a/src/main/java/com/alibaba/druid/support/logging/JakartaCommonsLoggingImpl.java +++ b/src/main/java/com/alibaba/druid/support/logging/JakartaCommonsLoggingImpl.java @@ -1,102 +1,102 @@ -/* - * Copyright 1999-2011 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.support.logging; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -public class JakartaCommonsLoggingImpl implements com.alibaba.druid.support.logging.Log { - - private Log log; - - private int errorCount; - private int warnCount; - private int infoCount; - - public JakartaCommonsLoggingImpl(Class clazz){ - log = LogFactory.getLog(clazz); - } - - public boolean isDebugEnabled() { - return log.isDebugEnabled(); - } - - public void error(String s, Throwable e) { - log.error(s, e); - errorCount++; - } - - public void error(String s) { - log.error(s); - errorCount++; - } - - public void debug(String s) { - log.debug(s); - } - - public void debug(String s, Throwable e) { - log.debug(s, e); - } - - public void warn(String s) { - log.warn(s); - warnCount++; - } - - @Override - public void warn(String s, Throwable e) { - log.warn(s, e); - warnCount++; - } - - @Override - public int getWarnCount() { - return warnCount; - } - - public int getErrorCount() { - return errorCount; - } - - @Override - public void resetStat() { - errorCount = 0; - warnCount = 0; - infoCount = 0; - } - - @Override - public boolean isInfoEnabled() { - return log.isInfoEnabled(); - } - - @Override - public void info(String msg) { - log.info(msg); - infoCount++; - } - - @Override - public int getInfoCount() { - return infoCount; - } - - @Override - public boolean isWarnEnabled() { - return log.isWarnEnabled(); - } -} +/* + * Copyright 1999-2011 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.support.logging; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class JakartaCommonsLoggingImpl implements com.alibaba.druid.support.logging.Log { + + private Log log; + + private int errorCount; + private int warnCount; + private int infoCount; + + public JakartaCommonsLoggingImpl(String loggerName){ + log = LogFactory.getLog(loggerName); + } + + public boolean isDebugEnabled() { + return log.isDebugEnabled(); + } + + public void error(String s, Throwable e) { + log.error(s, e); + errorCount++; + } + + public void error(String s) { + log.error(s); + errorCount++; + } + + public void debug(String s) { + log.debug(s); + } + + public void debug(String s, Throwable e) { + log.debug(s, e); + } + + public void warn(String s) { + log.warn(s); + warnCount++; + } + + @Override + public void warn(String s, Throwable e) { + log.warn(s, e); + warnCount++; + } + + @Override + public int getWarnCount() { + return warnCount; + } + + public int getErrorCount() { + return errorCount; + } + + @Override + public void resetStat() { + errorCount = 0; + warnCount = 0; + infoCount = 0; + } + + @Override + public boolean isInfoEnabled() { + return log.isInfoEnabled(); + } + + @Override + public void info(String msg) { + log.info(msg); + infoCount++; + } + + @Override + public int getInfoCount() { + return infoCount; + } + + @Override + public boolean isWarnEnabled() { + return log.isWarnEnabled(); + } +} diff --git a/src/main/java/com/alibaba/druid/support/logging/Jdk14LoggingImpl.java b/src/main/java/com/alibaba/druid/support/logging/Jdk14LoggingImpl.java index 502790474f..2b6004f75d 100644 --- a/src/main/java/com/alibaba/druid/support/logging/Jdk14LoggingImpl.java +++ b/src/main/java/com/alibaba/druid/support/logging/Jdk14LoggingImpl.java @@ -1,105 +1,105 @@ -/* - * Copyright 1999-2011 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.support.logging; - -import java.util.logging.Level; -import java.util.logging.Logger; - -public class Jdk14LoggingImpl implements Log { - - private Logger log; - - private int errorCount; - private int warnCount; - private int infoCount; - - private String clazzName; - - public Jdk14LoggingImpl(Class clazz){ - clazzName = clazz.getName(); - log = Logger.getLogger(clazzName); - } - - public boolean isDebugEnabled() { - return log.isLoggable(Level.FINE); - } - - public void error(String s, Throwable e) { - log.logp(Level.SEVERE,clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), s, e); - errorCount++; - } - - public void error(String s) { - log.logp(Level.SEVERE,clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), s); - errorCount++; - } - - public void debug(String s) { - log.logp(Level.FINE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), s); - } - - public void debug(String s, Throwable e) { - log.logp(Level.FINE, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), s, e); - } - - public void warn(String s) { - log.logp(Level.WARNING, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), s); - warnCount++; - } - - @Override - public void warn(String s, Throwable e) { - log.logp(Level.WARNING, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), s, e); - warnCount++; - } - - @Override - public int getWarnCount() { - return warnCount; - } - - public int getErrorCount() { - return errorCount; - } - - @Override - public void resetStat() { - errorCount = 0; - warnCount = 0; - infoCount = 0; - } - - @Override - public boolean isInfoEnabled() { - return log.isLoggable(Level.INFO); - } - - @Override - public void info(String msg) { - log.logp(Level.INFO, clazzName, Thread.currentThread().getStackTrace()[1].getMethodName(), msg); - infoCount++; - } - - @Override - public int getInfoCount() { - return infoCount; - } - - @Override - public boolean isWarnEnabled() { - return log.isLoggable(Level.WARNING); - } -} +/* + * Copyright 1999-2011 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.support.logging; + +import java.util.logging.Level; +import java.util.logging.Logger; + +public class Jdk14LoggingImpl implements Log { + + private Logger log; + + private int errorCount; + private int warnCount; + private int infoCount; + + private String loggerName; + + public Jdk14LoggingImpl(String loggerName){ + this.loggerName = loggerName; + log = Logger.getLogger(loggerName); + } + + public boolean isDebugEnabled() { + return log.isLoggable(Level.FINE); + } + + public void error(String s, Throwable e) { + log.logp(Level.SEVERE, loggerName, Thread.currentThread().getStackTrace()[1].getMethodName(), s, e); + errorCount++; + } + + public void error(String s) { + log.logp(Level.SEVERE, loggerName, Thread.currentThread().getStackTrace()[1].getMethodName(), s); + errorCount++; + } + + public void debug(String s) { + log.logp(Level.FINE, loggerName, Thread.currentThread().getStackTrace()[1].getMethodName(), s); + } + + public void debug(String s, Throwable e) { + log.logp(Level.FINE, loggerName, Thread.currentThread().getStackTrace()[1].getMethodName(), s, e); + } + + public void warn(String s) { + log.logp(Level.WARNING, loggerName, Thread.currentThread().getStackTrace()[1].getMethodName(), s); + warnCount++; + } + + @Override + public void warn(String s, Throwable e) { + log.logp(Level.WARNING, loggerName, Thread.currentThread().getStackTrace()[1].getMethodName(), s, e); + warnCount++; + } + + @Override + public int getWarnCount() { + return warnCount; + } + + public int getErrorCount() { + return errorCount; + } + + @Override + public void resetStat() { + errorCount = 0; + warnCount = 0; + infoCount = 0; + } + + @Override + public boolean isInfoEnabled() { + return log.isLoggable(Level.INFO); + } + + @Override + public void info(String msg) { + log.logp(Level.INFO, loggerName, Thread.currentThread().getStackTrace()[1].getMethodName(), msg); + infoCount++; + } + + @Override + public int getInfoCount() { + return infoCount; + } + + @Override + public boolean isWarnEnabled() { + return log.isLoggable(Level.WARNING); + } +} diff --git a/src/main/java/com/alibaba/druid/support/logging/Log4jImpl.java b/src/main/java/com/alibaba/druid/support/logging/Log4jImpl.java index 2315e5363e..a9040b1e83 100644 --- a/src/main/java/com/alibaba/druid/support/logging/Log4jImpl.java +++ b/src/main/java/com/alibaba/druid/support/logging/Log4jImpl.java @@ -1,101 +1,101 @@ -/* - * Copyright 1999-2011 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.support.logging; - -import org.apache.log4j.Level; -import org.apache.log4j.Logger; - -public class Log4jImpl implements Log { - - private static final String callerFQCN = Log4jImpl.class.getName(); - - private Logger log; - - private int errorCount; - private int warnCount; - private int infoCount; - - public Log4jImpl(Class clazz){ - log = Logger.getLogger(clazz); - } - - public boolean isDebugEnabled() { - return log.isDebugEnabled(); - } - - public void error(String s, Throwable e) { - errorCount++; - log.log(callerFQCN, Level.ERROR, s, e); - } - - public void error(String s) { - errorCount++; - log.log(callerFQCN, Level.ERROR, s, null); - } - - public void debug(String s) { - log.log(callerFQCN, Level.DEBUG, s, null); - } - - public void debug(String s, Throwable e) { - log.log(callerFQCN, Level.DEBUG, s, e); - } - - public void warn(String s) { - log.log(callerFQCN, Level.WARN, s, null); - warnCount++; - } - - public void warn(String s, Throwable e) { - log.log(callerFQCN, Level.WARN, s, e); - warnCount++; - } - - public int getWarnCount() { - return warnCount; - } - - public int getErrorCount() { - return errorCount; - } - - public void resetStat() { - errorCount = 0; - warnCount = 0; - infoCount = 0; - } - - public boolean isInfoEnabled() { - return log.isInfoEnabled(); - } - - public void info(String msg) { - infoCount++; - log.log(callerFQCN, Level.INFO, msg, null); - } - - public boolean isWarnEnabled() { - return log.isEnabledFor(Level.WARN); - } - - public int getInfoCount() { - return infoCount; - } - - public String toString() { - return log.toString(); - } -} +/* + * Copyright 1999-2011 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.support.logging; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +public class Log4jImpl implements Log { + + private static final String callerFQCN = Log4jImpl.class.getName(); + + private Logger log; + + private int errorCount; + private int warnCount; + private int infoCount; + + public Log4jImpl(String loggerName){ + log = Logger.getLogger(loggerName); + } + + public boolean isDebugEnabled() { + return log.isDebugEnabled(); + } + + public void error(String s, Throwable e) { + errorCount++; + log.log(callerFQCN, Level.ERROR, s, e); + } + + public void error(String s) { + errorCount++; + log.log(callerFQCN, Level.ERROR, s, null); + } + + public void debug(String s) { + log.log(callerFQCN, Level.DEBUG, s, null); + } + + public void debug(String s, Throwable e) { + log.log(callerFQCN, Level.DEBUG, s, e); + } + + public void warn(String s) { + log.log(callerFQCN, Level.WARN, s, null); + warnCount++; + } + + public void warn(String s, Throwable e) { + log.log(callerFQCN, Level.WARN, s, e); + warnCount++; + } + + public int getWarnCount() { + return warnCount; + } + + public int getErrorCount() { + return errorCount; + } + + public void resetStat() { + errorCount = 0; + warnCount = 0; + infoCount = 0; + } + + public boolean isInfoEnabled() { + return log.isInfoEnabled(); + } + + public void info(String msg) { + infoCount++; + log.log(callerFQCN, Level.INFO, msg, null); + } + + public boolean isWarnEnabled() { + return log.isEnabledFor(Level.WARN); + } + + public int getInfoCount() { + return infoCount; + } + + public String toString() { + return log.toString(); + } +} diff --git a/src/main/java/com/alibaba/druid/support/logging/LogFactory.java b/src/main/java/com/alibaba/druid/support/logging/LogFactory.java index 9cd67ae2ed..04be43ea72 100644 --- a/src/main/java/com/alibaba/druid/support/logging/LogFactory.java +++ b/src/main/java/com/alibaba/druid/support/logging/LogFactory.java @@ -1,109 +1,101 @@ -/* - * Copyright 1999-2011 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.support.logging; - -import java.lang.reflect.Constructor; - -@SuppressWarnings("rawtypes") -public class LogFactory { - - private static Constructor logConstructor; - - static { - // TODO add slf4j logging - - // 优先选择log4j,而非Apache Common Logging. 因为后者无法设置真实Log调用者的信息 - tryImplementation("org.apache.log4j.Logger", "com.alibaba.druid.support.logging.Log4jImpl"); - tryImplementation("java.util.logging.Logger", "com.alibaba.druid.support.logging.Jdk14LoggingImpl"); - tryImplementation("org.slf4j.Logger", "com.alibaba.druid.support.logging.SLF4JImpl"); - tryImplementation("org.apache.commons.logging.LogFactory", - "com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl"); - - if (logConstructor == null) { - try { - logConstructor = NoLoggingImpl.class.getConstructor(Class.class); - } catch (Exception e) { - throw new IllegalStateException(e.getMessage(), e); - } - } - } - - @SuppressWarnings("unchecked") - private static void tryImplementation(String testClassName, String implClassName) { - if (logConstructor != null) { - return; - } - - try { - Resources.classForName(testClassName); - Class implClass = Resources.classForName(implClassName); - logConstructor = implClass.getConstructor(new Class[] { Class.class }); - - Class declareClass = logConstructor.getDeclaringClass(); - if (!Log.class.isAssignableFrom(declareClass)) { - logConstructor = null; - } - - try { - logConstructor.newInstance(LogFactory.class); - } catch (Throwable t) { - logConstructor = null; - } - } catch (Throwable t) { - // skip - } - } - - public static Log getLog(Class aClass) { - try { - return (Log) logConstructor.newInstance(new Object[] { aClass }); - } catch (Throwable t) { - throw new RuntimeException("Error creating logger for class " + aClass + ". Cause: " + t, t); - } - } - - /** - * This method will switch the logging implementation to Log4J if Log4J is available on the classpath. This is - * useful in situations where you want to use Log4J to log iBATIS activity but commons logging is on the classpath. - * Note that this method is only effective for log classes obtained after calling this method. If you intend to use - * this method you should call it before calling any other iBATIS method. - */ - @SuppressWarnings("unchecked") - public static synchronized void selectLog4JLogging() { - try { - Resources.classForName("org.apache.log4j.Logger"); - Class implClass = Resources.classForName("com.alibaba.druid.support.logging.Log4jImpl"); - logConstructor = implClass.getConstructor(new Class[] { Class.class }); - } catch (Throwable t) { - } - } - - /** - * This method will switch the logging implementation to Java native logging if you are running in JRE 1.4 or above. - * This is useful in situations where you want to use Java native logging to log iBATIS activity but commons logging - * or Log4J is on the classpath. Note that this method is only effective for log classes obtained after calling this - * method. If you intend to use this method you should call it before calling any other iBATIS method. - */ - @SuppressWarnings("unchecked") - public static synchronized void selectJavaLogging() { - try { - Resources.classForName("java.util.logging.Logger"); - Class implClass = Resources.classForName("com.alibaba.druid.support.logging.Jdk14LoggingImpl"); - logConstructor = implClass.getConstructor(new Class[] { Class.class }); - } catch (Throwable t) { - } - } -} +/* + * Copyright 1999-2011 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.support.logging; + +import java.lang.reflect.Constructor; + +@SuppressWarnings("rawtypes") +public class LogFactory { + + private static Constructor logConstructor; + + static { + // TODO add slf4j logging + + // 优先选择log4j,而非Apache Common Logging. 因为后者无法设置真实Log调用者的信息 + tryImplementation("org.apache.log4j.Logger", "com.alibaba.druid.support.logging.Log4jImpl"); + tryImplementation("java.util.logging.Logger", "com.alibaba.druid.support.logging.Jdk14LoggingImpl"); + tryImplementation("org.slf4j.Logger", "com.alibaba.druid.support.logging.SLF4JImpl"); + tryImplementation("org.apache.commons.logging.LogFactory", + "com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl"); + + if (logConstructor == null) { + try { + logConstructor = NoLoggingImpl.class.getConstructor(String.class); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + } + + @SuppressWarnings("unchecked") + private static void tryImplementation(String testClassName, String implClassName) { + if (logConstructor != null) { + return; + } + + try { + Resources.classForName(testClassName); + Class implClass = Resources.classForName(implClassName); + logConstructor = implClass.getConstructor(new Class[] { String.class }); + + Class declareClass = logConstructor.getDeclaringClass(); + if (!Log.class.isAssignableFrom(declareClass)) { + logConstructor = null; + } + + try { + logConstructor.newInstance(LogFactory.class.getName()); + } catch (Throwable t) { + logConstructor = null; + } + } catch (Throwable t) { + // skip + } + } + + public static Log getLog(Class clazz) { + return getLog(clazz.getName()); + } + + public static Log getLog(String loggerName) { + try { + return (Log) logConstructor.newInstance(new Object[] { loggerName }); + } catch (Throwable t) { + throw new RuntimeException("Error creating logger for logger '" + loggerName + "'. Cause: " + t, t); + } + } + + @SuppressWarnings("unchecked") + public static synchronized void selectLog4JLogging() { + try { + Resources.classForName("org.apache.log4j.Logger"); + Class implClass = Resources.classForName("com.alibaba.druid.support.logging.Log4jImpl"); + logConstructor = implClass.getConstructor(new Class[] { String.class }); + } catch (Throwable t) { + } + } + + @SuppressWarnings("unchecked") + public static synchronized void selectJavaLogging() { + try { + Resources.classForName("java.util.logging.Logger"); + Class implClass = Resources.classForName("com.alibaba.druid.support.logging.Jdk14LoggingImpl"); + logConstructor = implClass.getConstructor(new Class[] { String.class }); + } catch (Throwable t) { + } + } +} diff --git a/src/main/java/com/alibaba/druid/support/logging/NoLoggingImpl.java b/src/main/java/com/alibaba/druid/support/logging/NoLoggingImpl.java index b30b574eba..c239bb53bc 100644 --- a/src/main/java/com/alibaba/druid/support/logging/NoLoggingImpl.java +++ b/src/main/java/com/alibaba/druid/support/logging/NoLoggingImpl.java @@ -1,97 +1,101 @@ -/* - * Copyright 1999-2011 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.support.logging; - -public class NoLoggingImpl implements Log { - - private int infoCount; - private int errorCount; - private int warnCount; - private Class clazz; - - public NoLoggingImpl(Class clazz){ - this.clazz = clazz; - } - - public boolean isDebugEnabled() { - return false; - } - - public void error(String s, Throwable e) { - error(s); - - if (e != null) { - e.printStackTrace(); - } - } - - public void error(String s) { - errorCount++; - if (s != null) { - System.err.println(clazz.getClass().getName() + " : " + s); - } - } - - public void debug(String s) { - } - - public void debug(String s, Throwable e) { - } - - public void warn(String s) { - warnCount++; - } - - @Override - public void warn(String s, Throwable e) { - warnCount++; - } - - public int getErrorCount() { - return errorCount; - } - - @Override - public int getWarnCount() { - return warnCount; - } - - @Override - public void resetStat() { - errorCount = 0; - warnCount = 0; - infoCount = 0; - } - - @Override - public boolean isInfoEnabled() { - return false; - } - - @Override - public void info(String s) { - infoCount++; - } - - @Override - public boolean isWarnEnabled() { - return false; - } - - public int getInfoCount() { - return infoCount; - } -} +/* + * Copyright 1999-2011 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.support.logging; + +public class NoLoggingImpl implements Log { + + private int infoCount; + private int errorCount; + private int warnCount; + private String loggerName; + + public NoLoggingImpl(String loggerName){ + this.loggerName = loggerName; + } + + public String getLoggerName() { + return this.loggerName; + } + + public boolean isDebugEnabled() { + return false; + } + + public void error(String s, Throwable e) { + error(s); + + if (e != null) { + e.printStackTrace(); + } + } + + public void error(String s) { + errorCount++; + if (s != null) { + System.err.println(loggerName + " : " + s); + } + } + + public void debug(String s) { + } + + public void debug(String s, Throwable e) { + } + + public void warn(String s) { + warnCount++; + } + + @Override + public void warn(String s, Throwable e) { + warnCount++; + } + + public int getErrorCount() { + return errorCount; + } + + @Override + public int getWarnCount() { + return warnCount; + } + + @Override + public void resetStat() { + errorCount = 0; + warnCount = 0; + infoCount = 0; + } + + @Override + public boolean isInfoEnabled() { + return false; + } + + @Override + public void info(String s) { + infoCount++; + } + + @Override + public boolean isWarnEnabled() { + return false; + } + + public int getInfoCount() { + return infoCount; + } +} diff --git a/src/main/java/com/alibaba/druid/support/logging/SLF4JImpl.java b/src/main/java/com/alibaba/druid/support/logging/SLF4JImpl.java index cc5ab7e659..0b4e56fa53 100644 --- a/src/main/java/com/alibaba/druid/support/logging/SLF4JImpl.java +++ b/src/main/java/com/alibaba/druid/support/logging/SLF4JImpl.java @@ -20,102 +20,104 @@ import org.slf4j.LoggerFactory; import org.slf4j.spi.LocationAwareLogger; public class SLF4JImpl implements Log { - private static final String callerFQCN = SLF4JImpl.class.getName(); - private static final Logger testLogger = LoggerFactory.getLogger(SLF4JImpl.class); - static { - //if the logger is not a LocationAwareLogger instance, it can not get correct stack StackTraceElement - //so ignore this implementation. - if (!(testLogger instanceof LocationAwareLogger)) { - throw new UnsupportedOperationException(testLogger.getClass()+" is not a suitable logger"); - } - } - private int errorCount; - private int warnCount; - private int infoCount; - private LocationAwareLogger log; - - public SLF4JImpl(Class clazz) { - Logger log = LoggerFactory.getLogger(clazz); - if (log instanceof LocationAwareLogger) { - this.log = (LocationAwareLogger) log; - } - } - - @Override - public boolean isDebugEnabled() { - return log.isDebugEnabled(); - } - - @Override - public void error(String msg, Throwable e) { - log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, e); - errorCount++; - } - - @Override - public void error(String msg) { - log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, null); - errorCount++; - } - - @Override - public boolean isInfoEnabled() { - return log.isInfoEnabled(); - } - - @Override - public void info(String msg) { - infoCount++; - log.log(null, callerFQCN, LocationAwareLogger.INFO_INT, msg, null, null); - } - - @Override - public void debug(String msg) { - log.log(null, callerFQCN, LocationAwareLogger.DEBUG_INT, msg, null, null); - } - - @Override - public void debug(String msg, Throwable e) { - log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, e); - } - - @Override - public boolean isWarnEnabled() { - return log.isWarnEnabled(); - } - - @Override - public void warn(String msg) { - log.log(null, callerFQCN, LocationAwareLogger.WARN_INT, msg, null, null); - warnCount++; - } - - @Override - public void warn(String msg, Throwable e) { - log.log(null, callerFQCN, LocationAwareLogger.WARN_INT, msg, null, e); - warnCount++; - } - - @Override - public int getErrorCount() { - return errorCount; - } - - @Override - public int getWarnCount() { - return warnCount; - } - - @Override - public int getInfoCount() { - return infoCount; - } - - @Override - public void resetStat() { - errorCount = 0; - warnCount = 0; - infoCount = 0; - } - + + private static final String callerFQCN = SLF4JImpl.class.getName(); + private static final Logger testLogger = LoggerFactory.getLogger(SLF4JImpl.class); + static { + // if the logger is not a LocationAwareLogger instance, it can not get correct stack StackTraceElement + // so ignore this implementation. + if (!(testLogger instanceof LocationAwareLogger)) { + throw new UnsupportedOperationException(testLogger.getClass() + " is not a suitable logger"); + } + } + private int errorCount; + private int warnCount; + private int infoCount; + private LocationAwareLogger log; + + public SLF4JImpl(Class clazz){ + this.log = (LocationAwareLogger) LoggerFactory.getLogger(clazz); + } + + public SLF4JImpl(String loggerName){ + this.log = (LocationAwareLogger) LoggerFactory.getLogger(loggerName); + } + + @Override + public boolean isDebugEnabled() { + return log.isDebugEnabled(); + } + + @Override + public void error(String msg, Throwable e) { + log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, e); + errorCount++; + } + + @Override + public void error(String msg) { + log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, null); + errorCount++; + } + + @Override + public boolean isInfoEnabled() { + return log.isInfoEnabled(); + } + + @Override + public void info(String msg) { + infoCount++; + log.log(null, callerFQCN, LocationAwareLogger.INFO_INT, msg, null, null); + } + + @Override + public void debug(String msg) { + log.log(null, callerFQCN, LocationAwareLogger.DEBUG_INT, msg, null, null); + } + + @Override + public void debug(String msg, Throwable e) { + log.log(null, callerFQCN, LocationAwareLogger.ERROR_INT, msg, null, e); + } + + @Override + public boolean isWarnEnabled() { + return log.isWarnEnabled(); + } + + @Override + public void warn(String msg) { + log.log(null, callerFQCN, LocationAwareLogger.WARN_INT, msg, null, null); + warnCount++; + } + + @Override + public void warn(String msg, Throwable e) { + log.log(null, callerFQCN, LocationAwareLogger.WARN_INT, msg, null, e); + warnCount++; + } + + @Override + public int getErrorCount() { + return errorCount; + } + + @Override + public int getWarnCount() { + return warnCount; + } + + @Override + public int getInfoCount() { + return infoCount; + } + + @Override + public void resetStat() { + errorCount = 0; + warnCount = 0; + infoCount = 0; + } + } diff --git a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java index 4314b367bc..12efca3080 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java @@ -57,6 +57,7 @@ import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLInsertInto; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause; import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource; import com.alibaba.druid.sql.ast.statement.SQLRollbackStatement; import com.alibaba.druid.sql.ast.statement.SQLSelect; @@ -1079,7 +1080,7 @@ public class WallVisitorUtils { } } - if (isWhereOrHaving(x)) { + if (!(x.getParent() instanceof ValuesClause)) { addViolation(visitor, ErrorCode.FUNCTION_DENY, "deny function : " + methodName, x); } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest_concat.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest_concat.java new file mode 100644 index 0000000000..350186435e --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest_concat.java @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2011 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.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.wall.WallProvider; +import com.alibaba.druid.wall.spi.MySqlWallProvider; + +public class MySqlWallTest_concat extends TestCase { + + public void test_true() throws Exception { + WallProvider provider = new MySqlWallProvider(); + + provider.getConfig().setSelectHavingAlwayTrueCheck(true); + + Assert.assertTrue(provider.checkValid(// + "select * from tb_product_word where name='' or CONCAT(name,style)='' or CONCAT(shop,style)='' or CONCAT(ename,style)=''")); + + Assert.assertEquals(1, provider.getTableStats().size()); + Assert.assertTrue(provider.getTableStats().containsKey("tb_product_word")); + } + +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/dynamic/DruidDataSourceStatLoggerImplTest.java b/src/test/java/com/alibaba/druid/bvt/pool/dynamic/DruidDataSourceStatLoggerImplTest.java new file mode 100644 index 0000000000..3252eb234f --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/dynamic/DruidDataSourceStatLoggerImplTest.java @@ -0,0 +1,49 @@ +package com.alibaba.druid.bvt.pool.dynamic; + +import java.lang.reflect.Field; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidDataSourceStatLogger; +import com.alibaba.druid.pool.DruidDataSourceStatLoggerImpl; +import com.alibaba.druid.support.logging.Log; + +public class DruidDataSourceStatLoggerImplTest extends TestCase { + + private DruidDataSource dataSource; + + private Log statLog; + + protected void setUp() throws Exception { + Field logField = DruidDataSourceStatLoggerImpl.class.getDeclaredField("LOG"); + logField.setAccessible(true); + statLog = (Log) logField.get(null); + + statLog.resetStat(); + + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + dataSource.setConnectionProperties("a=3;b=4"); + dataSource.setFilters("stat"); + dataSource.init(); + + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_connectPropertiesChange() throws Exception { + Assert.assertTrue(dataSource.isWrapperFor(DruidDataSourceStatLogger.class)); + Assert.assertTrue(dataSource.isWrapperFor(DruidDataSourceStatLoggerImpl.class)); + DruidDataSourceStatLoggerImpl loggerImpl = dataSource.unwrap(DruidDataSourceStatLoggerImpl.class); + Assert.assertSame(statLog, loggerImpl.getLogger()); + + dataSource.setConnectionProperties("druid.stat.loggerName=xxx"); + Assert.assertNotSame(statLog, loggerImpl.getLogger()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/vendor/MySqlValidConnectionCheckerTest.java b/src/test/java/com/alibaba/druid/bvt/pool/vendor/MySqlValidConnectionCheckerTest.java deleted file mode 100644 index 8eafedbc71..0000000000 --- a/src/test/java/com/alibaba/druid/bvt/pool/vendor/MySqlValidConnectionCheckerTest.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.alibaba.druid.bvt.pool.vendor; - -import junit.framework.TestCase; - - -public class MySqlValidConnectionCheckerTest extends TestCase { - -} diff --git a/src/test/java/com/alibaba/druid/bvt/stat/DruidStatServiceTest.java b/src/test/java/com/alibaba/druid/bvt/stat/DruidStatServiceTest.java index d95be562f6..434f99f41b 100644 --- a/src/test/java/com/alibaba/druid/bvt/stat/DruidStatServiceTest.java +++ b/src/test/java/com/alibaba/druid/bvt/stat/DruidStatServiceTest.java @@ -204,8 +204,9 @@ public class DruidStatServiceTest extends TestCase { String result = DruidStatService.getInstance().service("/activeConnectionStackTrace.json"); Map resultMap = (Map) JSONUtils.parse(result); List contentList = (List) resultMap.get("Content"); + Object first = contentList.get(0); - assertThat(contentList.get(0), is(not(nullValue()))); + assertThat(first, is(not(nullValue()))); // close connection at last. stmt.close(); conn.close(); diff --git a/src/test/java/com/alibaba/druid/bvt/stat/DruidStatServiceTest2.java b/src/test/java/com/alibaba/druid/bvt/stat/DruidStatServiceTest2.java index eaa8263522..0a5ad3a9fd 100644 --- a/src/test/java/com/alibaba/druid/bvt/stat/DruidStatServiceTest2.java +++ b/src/test/java/com/alibaba/druid/bvt/stat/DruidStatServiceTest2.java @@ -23,9 +23,12 @@ import static org.junit.Assert.assertThat; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.util.Collections; import java.util.List; import java.util.Map; +import junit.framework.TestCase; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -38,13 +41,12 @@ import com.alibaba.druid.util.JdbcUtils; /** * Multiple data source test case. */ -public class DruidStatServiceTest2 { +public class DruidStatServiceTest2 extends TestCase { private DruidDataSource dataSource; private DruidDataSource dataSource2; // every test, two data source initialized. - @Before public void setUp() throws Exception { // DruidStatService is singleton, reset all for other testcase. DruidStatService.getInstance().service("/reset-all.json"); @@ -62,13 +64,11 @@ public class DruidStatServiceTest2 { dataSource2.init(); } - @After public void tearDown() throws Exception { JdbcUtils.close(dataSource); JdbcUtils.close(dataSource2); } - @Test public void test_statService_getSqlList() throws Exception { String sql = "select 1"; @@ -106,7 +106,6 @@ public class DruidStatServiceTest2 { } } - @Test public void test_statService_getSqlById() throws Exception { String sql = "select 1"; @@ -155,7 +154,6 @@ public class DruidStatServiceTest2 { assertThat(resultMap.get("Content"), is(nullValue())); } - @Test public void test_statService_getDataSourceList() throws Exception { String result = DruidStatService.getInstance().service("/datasource.json"); Map resultMap = (Map) JSONUtils.parse(result); @@ -167,5 +165,9 @@ public class DruidStatServiceTest2 { assertThat((Integer) dataSourceStat.get("PoolingCount"), equalTo(0)); assertThat((Integer) dataSourceStat.get("ActiveCount"), equalTo(0)); } + + public void test_getWallStatMap() throws Exception { + DruidStatService.getInstance().getWallStatMap(Collections.emptyMap()); + } }