From 339e5f944f419f9198ddd44f96c20948aa3c2e4b Mon Sep 17 00:00:00 2001 From: zhouhaibin <283595276@qq.com> Date: Fri, 10 Aug 2012 12:45:48 +0800 Subject: [PATCH 01/10] Merge remote-tracking branch 'zhb/master' Conflicts: src/main/java/com/alibaba/druid/support/http/StatViewServlet.java --- .../alibaba/druid/filter/stat/StatFilter.java | 7 +- .../druid/pool/DataSourceClosedException.java | 21 ++ .../alibaba/druid/pool/DruidDataSource.java | 40 ++- .../DruidDataSourceStatDefaultStrategy.java | 204 +++++++++++++ .../DruidDataSourceStatJNDIStatStrategy.java | 53 ++++ .../stat/DruidDataSourceStatStrategy.java | 22 ++ .../DruidDataSourceStatStrategyContext.java | 44 +++ .../druid/stat/DruidStatManagerFacade.java | 271 +++--------------- .../com/alibaba/druid/stat/JdbcSqlStat.java | 8 +- .../druid/support/JSONDruidStatService.java | 16 +- .../druid/support/http/StatViewServlet.java | 53 ++-- .../alibaba/druid/util/ReflectionUtils.java | 25 +- .../com/alibaba/druid/util/StringUtils.java | 6 + .../alibaba/druid/bvt/pool/ClosedTest.java | 32 +++ .../druid/bvt/pool/ConfigErrorTest.java | 13 +- .../druid/bvt/pool/ConfigErrorTest2.java | 13 +- .../druid/bvt/pool/ConfigErrorTest3.java | 14 +- .../druid/bvt/pool/SlowSqlMillisTest.java | 32 +++ .../druid/bvt/pool/SlowSqlMillisTest2.java | 38 +++ test.html | 0 20 files changed, 611 insertions(+), 301 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/pool/DataSourceClosedException.java create mode 100644 src/main/java/com/alibaba/druid/stat/DruidDataSourceStatDefaultStrategy.java create mode 100644 src/main/java/com/alibaba/druid/stat/DruidDataSourceStatJNDIStatStrategy.java create mode 100644 src/main/java/com/alibaba/druid/stat/DruidDataSourceStatStrategy.java create mode 100644 src/main/java/com/alibaba/druid/stat/DruidDataSourceStatStrategyContext.java create mode 100644 src/test/java/com/alibaba/druid/bvt/pool/ClosedTest.java create mode 100644 src/test/java/com/alibaba/druid/bvt/pool/SlowSqlMillisTest.java create mode 100644 src/test/java/com/alibaba/druid/bvt/pool/SlowSqlMillisTest2.java create mode 100644 test.html diff --git a/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java b/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java index 2ffd9e4e89..615097cdff 100644 --- a/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java +++ b/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java @@ -96,6 +96,10 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean { this.dbType = dbType; } + public long getSlowSqlMillis() { + return slowSqlMillis; + } + public boolean isConnectionStackTraceEnable() { return connectionStackTraceEnable; } @@ -406,7 +410,8 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean { } } - private final void internalAfterStatementExecute(StatementProxy statement, boolean firstResult, int... updateCountArray) { + private final void internalAfterStatementExecute(StatementProxy statement, boolean firstResult, + int... updateCountArray) { final JdbcStatementStat.Entry entry = getStatementInfo(statement); diff --git a/src/main/java/com/alibaba/druid/pool/DataSourceClosedException.java b/src/main/java/com/alibaba/druid/pool/DataSourceClosedException.java new file mode 100644 index 0000000000..c003909874 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/DataSourceClosedException.java @@ -0,0 +1,21 @@ +package com.alibaba.druid.pool; + +import java.sql.SQLException; + +public class DataSourceClosedException extends SQLException { + + private static final long serialVersionUID = 1L; + + public DataSourceClosedException(){ + super(); + } + + public DataSourceClosedException(String reason){ + super(reason); + } + + public DataSourceClosedException(Throwable cause){ + super(cause); + } + +} diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index f29afaa9af..75735e20a5 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -72,7 +72,7 @@ import com.alibaba.druid.util.JdbcUtils; */ public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource { - public final static Log LOG = LogFactory.getLog(DruidDataSource.class); + private final static Log LOG = LogFactory.getLog(DruidDataSource.class); private static final long serialVersionUID = 1L; @@ -117,6 +117,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat private String initStackTrace; private boolean closed = false; + private long closeTimeMillis = -1L; private JdbcDataSourceStat dataSourceStat; @@ -274,23 +275,23 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat if (this.driverClass != null) { this.driverClass = driverClass.trim(); } - + if (isTestOnBorrow() || isTestOnReturn() || isTestWhileIdle()) { if (this.getValidationQuery() == null || this.getValidationQuery().length() == 0) { 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"); } } @@ -301,9 +302,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat if (jdbcUrl.startsWith(DruidDriver.DEFAULT_PREFIX)) { 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(); @@ -366,7 +367,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } else if (realDriverClassName.equals("com.alibaba.druid.mock.MockDriver")) { this.exceptionSorter = new MockExceptionSorter(); } - + if (realDriverClassName.equals("com.mysql.jdbc.Driver")) { if (this.isPoolPreparedStatements()) { LOG.error("mysql should not use 'PoolPreparedStatements'"); @@ -554,6 +555,11 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } try { + if (closed) { + connectErrorCount.incrementAndGet(); + throw new DataSourceClosedException("dataSource already closed at " + new Date(closeTimeMillis)); + } + if (!enable) { connectErrorCount.incrementAndGet(); throw new DataSourceDisableException(); @@ -775,6 +781,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat notEmptySignalCount++; this.closed = true; + this.closeTimeMillis = System.currentTimeMillis(); for (Filter filter : filters) { filter.destory(); @@ -782,6 +789,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat } finally { lock.unlock(); } + + LOG.warn("dataSource " + this.getID() + " closed"); } void incrementCreateCount() { @@ -879,7 +888,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat if (createError != null) { throw new GetConnectionTimeoutException(createError); } else { - throw new GetConnectionTimeoutException("loopWaitCount " + i + ", wait millis " + (nanos - estimate)/(1000 * 1000)); + throw new GetConnectionTimeoutException("loopWaitCount " + i + ", wait millis " + + (nanos - estimate) / (1000 * 1000)); } } } @@ -1105,11 +1115,11 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat for (; iter.hasNext();) { Map.Entry entry = iter.next(); DruidPooledConnection pooledConnection = entry.getKey(); - + if (pooledConnection.isRunning()) { continue; } - + ActiveConnectionTraceInfo activeInfo = entry.getValue(); long timeMillis = currentMillis - activeInfo.getConnectTime(); @@ -1447,15 +1457,15 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat 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); } diff --git a/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatDefaultStrategy.java b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatDefaultStrategy.java new file mode 100644 index 0000000000..4e692646d8 --- /dev/null +++ b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatDefaultStrategy.java @@ -0,0 +1,204 @@ +package com.alibaba.druid.stat; + +import java.sql.Driver; +import java.sql.DriverManager; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.management.JMException; + +import com.alibaba.druid.VERSION; +import com.alibaba.druid.pool.DruidDataSource; + +public class DruidDataSourceStatDefaultStrategy implements DruidDataSourceStatStrategy { + + private Set getDruidDataSourceInstances() { + return DruidDataSourceStatManager.getDruidDataSourceInstances(); + } + + public void resetDataSourceStat() { + DruidDataSourceStatManager.getInstance().reset(); + } + + public void resetSqlStat() { + JdbcStatManager.getInstance().reset(); + } + + public void resetAll() { + resetSqlStat(); + resetDataSourceStat(); + } + + private JdbcSqlStat getSqlStatById(Integer id) { + + for (DruidDataSource ds : getDruidDataSourceInstances()) { + JdbcSqlStat sqlStat = ds.getDataSourceStat().getSqlStat(id); + if (sqlStat != null) + return sqlStat; + } + return null; + } + + public Map getDataSourceStatData(Integer id) { + if (id == null) { + return null; + } + DruidDataSource datasource = getDruidDataSourceById(id); + return datasource == null ? null : dataSourceToMapData(datasource); + } + + private DruidDataSource getDruidDataSourceById(Integer identity) { + + if (identity == null) { + return null; + } + + for (DruidDataSource datasource : getDruidDataSourceInstances()) { + if (System.identityHashCode(datasource) == identity) { + return datasource; + } + } + return null; + } + + public List> getSqlStatDataList() { + List> result = new ArrayList>(); + for (DruidDataSource datasource : getDruidDataSourceInstances()) { + for (JdbcSqlStat sqlStat : datasource.getDataSourceStat().getSqlStatMap().values()) { + if (sqlStat.getExecuteCount() == 0 && sqlStat.getRunningCount() == 0) { + continue; + } + + result.add(getSqlStatData(sqlStat)); + } + } + return result; + } + + public Map getSqlStatData(Integer id) { + if (id == null) { + return null; + } + JdbcSqlStat sqlStat = getSqlStatById(id); + return sqlStat == null ? null : getSqlStatData(sqlStat); + } + + private Map getSqlStatData(JdbcSqlStat sqlStat) { + try { + return sqlStat.getData(); + } catch (JMException e) { + } + return null; + } + + public List getDataSourceStatList() { + List datasourceList = new ArrayList(); + for (DruidDataSource dataSource : getDruidDataSourceInstances()) { + datasourceList.add(dataSourceToMapData(dataSource)); + } + return datasourceList; + } + + public Map returnJSONBasicStat() { + Map dataMap = new LinkedHashMap(); + dataMap.put("Version", VERSION.getVersionNumber()); + dataMap.put("Drivers", getDriversData()); + return dataMap; + } + + private List getDriversData() { + List drivers = new ArrayList(); + for (Enumeration e = DriverManager.getDrivers(); e.hasMoreElements();) { + Driver driver = e.nextElement(); + drivers.add(driver.getClass().getName()); + } + return drivers; + } + + public List> getPoolingConnectionInfoByDataSourceId(Integer id) { + DruidDataSource datasource = getDruidDataSourceById(id); + if (datasource == null) + return null; + return datasource.getPoolingConnectionInfo(); + } + + public List getActiveConnectionStackTraceByDataSourceId(Integer id) { + DruidDataSource datasource = getDruidDataSourceById(id); + if (datasource == null || !datasource.isRemoveAbandoned()) + return null; + + return datasource.getActiveConnectionStackTrace(); + } + + private Map dataSourceToMapData(DruidDataSource dataSource) { + + Map dataMap = new LinkedHashMap(); + dataMap.put("Identity", System.identityHashCode(dataSource)); + dataMap.put("Name", dataSource.getName()); + dataMap.put("DbType", dataSource.getDbType()); + dataMap.put("DriverClassName", dataSource.getDriverClassName()); + + dataMap.put("URL", dataSource.getUrl()); + dataMap.put("UserName", dataSource.getUsername()); + dataMap.put("FilterClassNames", dataSource.getFilterClassNames()); + + dataMap.put("WaitThreadCount", dataSource.getWaitThreadCount()); + dataMap.put("NotEmptyWaitCount", dataSource.getNotEmptyWaitCount()); + dataMap.put("NotEmptyWaitMillis", dataSource.getNotEmptyWaitMillis()); + + dataMap.put("PoolingCount", dataSource.getPoolingCount()); + dataMap.put("PoolingPeak", dataSource.getPoolingPeak()); + dataMap.put("PoolingPeakTime", dataSource.getPoolingPeakTime() == null ? null : dataSource.getPoolingPeakTime().toString()); + + dataMap.put("ActiveCount", dataSource.getActiveCount()); + dataMap.put("ActivePeak", dataSource.getActivePeak()); + dataMap.put("ActivePeakTime", dataSource.getActivePeakTime() == null ? null : dataSource.getActivePeakTime().toString()); + + dataMap.put("InitialSize", dataSource.getInitialSize()); + dataMap.put("MinIdle", dataSource.getMinIdle()); + dataMap.put("MaxActive", dataSource.getMaxActive()); + + dataMap.put("QueryTimeout", dataSource.getQueryTimeout()); + dataMap.put("TransactionQueryTimeout", dataSource.getTransactionQueryTimeout()); + dataMap.put("LoginTimeout", dataSource.getLoginTimeout()); + dataMap.put("ValidConnectionCheckerClassName", dataSource.getValidConnectionCheckerClassName()); + dataMap.put("ExceptionSorterClassName", dataSource.getExceptionSorterClassName()); + + dataMap.put("TestOnBorrow", dataSource.isTestOnBorrow()); + dataMap.put("TestOnReturn", dataSource.isTestOnReturn()); + dataMap.put("TestWhileIdle", dataSource.isTestWhileIdle()); + + dataMap.put("DefaultAutoCommit", dataSource.isDefaultAutoCommit()); + dataMap.put("DefaultReadOnly", dataSource.isDefaultAutoCommit()); + dataMap.put("DefaultTransactionIsolation", dataSource.getDefaultTransactionIsolation()); + + dataMap.put("LogicConnectCount", dataSource.getConnectCount()); + dataMap.put("LogicCloseCount", dataSource.getCloseCount()); + dataMap.put("LogicConnectErrorCount", dataSource.getConnectErrorCount()); + + dataMap.put("PhysicalConnectCount", dataSource.getCreateCount()); + dataMap.put("PhysicalCloseCount", dataSource.getDestroyCount()); + dataMap.put("PhysicalConnectErrorCount", dataSource.getCreateErrorCount()); + + dataMap.put("ExecuteCount", dataSource.getExecuteCount()); + dataMap.put("ErrorCount", dataSource.getErrorCount()); + dataMap.put("CommitCount", dataSource.getCommitCount()); + dataMap.put("RollbackCount", dataSource.getRollbackCount()); + + dataMap.put("PSCacheAccessCount", dataSource.getCachedPreparedStatementAccessCount()); + dataMap.put("PSCacheHitCount", dataSource.getCachedPreparedStatementHitCount()); + dataMap.put("PSCacheMissCount", dataSource.getCachedPreparedStatementMissCount()); + + dataMap.put("StartTransactionCount", dataSource.getStartTransactionCount()); + dataMap.put("TransactionHistogram", dataSource.getTransactionHistogramValues()); + + dataMap.put("ConnectionHoldTimeHistogram", dataSource.getDataSourceStat().getConnectionHoldHistogram().toArray()); + dataMap.put("RemoveAbandoned", dataSource.isRemoveAbandoned()); + + return dataMap; + } +} diff --git a/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatJNDIStatStrategy.java b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatJNDIStatStrategy.java new file mode 100644 index 0000000000..d8026865f4 --- /dev/null +++ b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatJNDIStatStrategy.java @@ -0,0 +1,53 @@ +package com.alibaba.druid.stat; + +import java.util.List; +import java.util.Map; + +import com.alibaba.druid.util.ReflectionUtils; + +public class DruidDataSourceStatJNDIStatStrategy implements DruidDataSourceStatStrategy{ + + private Object getStrategyB() { + return ReflectionUtils.getClassFromWebContainerOrCurrentClassLoader("com.alibaba.druid.stat.DruidDataSourceStatDefaultStrategy"); + } + + @SuppressWarnings("unchecked") + public Map getSqlStatData(Integer id) { + return (Map) ReflectionUtils.callObjectMethod(getStrategyB(), "getSqlStatData", id); + } + + @SuppressWarnings("unchecked") + public List> getSqlStatDataList() { + return (List>) ReflectionUtils.callObjectMethod(getStrategyB(), "getSqlStatDataList"); + } + + @SuppressWarnings("unchecked") + public List getActiveConnectionStackTraceByDataSourceId(Integer id) { + return (List) ReflectionUtils.callObjectMethod(getStrategyB(), "getActiveConnectionStackTraceByDataSourceId", id); + } + + @SuppressWarnings("unchecked") + public Map returnJSONBasicStat() { + return (Map) ReflectionUtils.callObjectMethod(getStrategyB(), "returnJSONBasicStat"); + } + + @SuppressWarnings("unchecked") + public List getDataSourceStatList() { + return (List) ReflectionUtils.callObjectMethod(getStrategyB(), "getDataSourceStatList"); + } + + @SuppressWarnings("unchecked") + public Map getDataSourceStatData(Integer id) { + return (Map) ReflectionUtils.callObjectMethod(getStrategyB(), "getDataSourceStatData", id); + } + + @SuppressWarnings("unchecked") + public List> getPoolingConnectionInfoByDataSourceId(Integer id) { + return (List>) ReflectionUtils.callObjectMethod(getStrategyB(), "getPoolingConnectionInfoByDataSourceId", id); + } + + public void resetAll() { + ReflectionUtils.callObjectMethod(getStrategyB(), "resetAll"); + } + +} diff --git a/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatStrategy.java b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatStrategy.java new file mode 100644 index 0000000000..aedb9279cf --- /dev/null +++ b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatStrategy.java @@ -0,0 +1,22 @@ +package com.alibaba.druid.stat; + +import java.util.List; +import java.util.Map; + +public interface DruidDataSourceStatStrategy { + public Map getSqlStatData(Integer id); + + public List> getSqlStatDataList(); + + public List getActiveConnectionStackTraceByDataSourceId(Integer id); + + public Map returnJSONBasicStat(); + + public List getDataSourceStatList(); + + public Map getDataSourceStatData(Integer id); + + public List> getPoolingConnectionInfoByDataSourceId(Integer id); + + public void resetAll(); +} diff --git a/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatStrategyContext.java b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatStrategyContext.java new file mode 100644 index 0000000000..4c02900eb8 --- /dev/null +++ b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatStrategyContext.java @@ -0,0 +1,44 @@ +package com.alibaba.druid.stat; + +import java.util.List; +import java.util.Map; + +public class DruidDataSourceStatStrategyContext { + private DruidDataSourceStatStrategy druidDataSourceStatStrategy; + + public DruidDataSourceStatStrategyContext(DruidDataSourceStatStrategy druidDataSourceStatStrategy) { + this.druidDataSourceStatStrategy = druidDataSourceStatStrategy; + } + + public Map getSqlStatData(Integer id) { + return druidDataSourceStatStrategy.getSqlStatData(id); + } + + public List> getSqlStatDataList() { + return druidDataSourceStatStrategy.getSqlStatDataList(); + } + + public List getActiveConnectionStackTraceByDataSourceId(Integer id) { + return druidDataSourceStatStrategy.getActiveConnectionStackTraceByDataSourceId(id); + } + + public Map returnJSONBasicStat() { + return druidDataSourceStatStrategy.returnJSONBasicStat(); + } + + public List getDataSourceStatList() { + return druidDataSourceStatStrategy.getDataSourceStatList(); + } + + public Map getDataSourceStatData(Integer id) { + return druidDataSourceStatStrategy.getDataSourceStatData(id); + } + + public List> getPoolingConnectionInfoByDataSourceId(Integer id) { + return druidDataSourceStatStrategy.getPoolingConnectionInfoByDataSourceId(id); + } + + public void resetAll() { + druidDataSourceStatStrategy.resetAll(); + } +} diff --git a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java index b28ca7d3bd..1b14851624 100644 --- a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java +++ b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java @@ -1,252 +1,67 @@ package com.alibaba.druid.stat; -import java.sql.Driver; -import java.sql.DriverManager; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.concurrent.locks.ReentrantLock; - -import javax.management.JMException; - -import com.alibaba.druid.VERSION; -import com.alibaba.druid.pool.DruidDataSource; -import com.alibaba.druid.util.ReflectionUtils; /** + * 监控相关的对外数据暴露 + * + *
+ * 1. 为了支持jndi数据源本类内部调用druid相关对象均需要反射调用,返回值也应该是Object,List,Map等无关于druid的类型
+ * 2. 对外暴露的public方法都应该先调用init(),应该有更好的方式,暂时没想到
+ * 
+ * 
  * @author sandzhang
  */
 public class DruidStatManagerFacade {
 
-    private final static DruidStatManagerFacade instance = new DruidStatManagerFacade();
+	private final static DruidStatManagerFacade instance = new DruidStatManagerFacade();
 
-    private boolean                             inited   = false;
+	private static DruidDataSourceStatStrategyContext ctx = null;
 
-    protected final ReentrantLock               lock     = new ReentrantLock(true);
+	private static DruidDataSourceStatStrategy strategy = null;
 
-    private DruidDataSourceStatManager          druidDataSourceStatManager;
-    private JdbcStatManager                     jdbcStatManager;
+	static {
+		strategy = new DruidDataSourceStatJNDIStatStrategy();
+		ctx = new DruidDataSourceStatStrategyContext(strategy);
+	}
 
-    private Set                datasourceInstances;
+	private DruidStatManagerFacade() {
+	}
 
-    private DruidStatManagerFacade() {
-    }
+	public static DruidStatManagerFacade getInstance() {
+		return instance;
+	}
 
-    public static DruidStatManagerFacade getInstance() {
-        return instance;
-    }
+	public Map getSqlStatData(Integer id) {
+		return ctx.getSqlStatData(id);
+	}
 
-    private void init() {
-        if (inited) {
-            return;
-        }
+	public List> getSqlStatDataList() {
+		return ctx.getSqlStatDataList();
+	}
 
-        lock.lock();
-        try {
-            if (inited) {
-                return;
-            }
+	public List getActiveConnectionStackTraceByDataSourceId(Integer id) {
+		return ctx.getActiveConnectionStackTraceByDataSourceId(id);
+	}
 
-            initByClassLoader();
+	public Map returnJSONBasicStat() {
+		return ctx.returnJSONBasicStat();
+	}
 
-            inited = true;
-        } finally {
-            lock.unlock();
-        }
-    }
+	public List getDataSourceStatList() {
+		return ctx.getDataSourceStatList();
+	}
 
-    @SuppressWarnings("unchecked")
-    private void initByClassLoader() {
-        Class druidDataSourceStatManagerClass = ReflectionUtils.getClassFromWebContainerOrCurrentClassLoader("com.alibaba.druid.stat.DruidDataSourceStatManager");
+	public Map getDataSourceStatData(Integer id) {
+		return ctx.getDataSourceStatData(id);
+	}
 
-        druidDataSourceStatManager = (DruidDataSourceStatManager) ReflectionUtils.callStaticMethod(druidDataSourceStatManagerClass,
-                                                                                                   "getInstance");
-        datasourceInstances = (Set) ReflectionUtils.callStaticMethod(druidDataSourceStatManagerClass,
-                                                                                      "getDruidDataSourceInstances");
+	public List> getPoolingConnectionInfoByDataSourceId(Integer id) {
+		return ctx.getPoolingConnectionInfoByDataSourceId(id);
+	}
 
-        Class jdbcStatManagerClass = ReflectionUtils.getClassFromWebContainerOrCurrentClassLoader("com.alibaba.druid.stat.JdbcStatManager");
-        jdbcStatManager = (JdbcStatManager) ReflectionUtils.callStaticMethod(jdbcStatManagerClass, "getInstance");
-
-    }
-
-    public Set getDruidDataSourceInstances() {
-        init();
-        return datasourceInstances;
-    }
-
-    public void resetDataSourceStat() {
-        init();
-        druidDataSourceStatManager.reset();
-    }
-
-    public void resetSqlStat() {
-        init();
-        jdbcStatManager.reset();
-    }
-
-    public void resetAll() {
-        init();
-        resetSqlStat();
-        resetDataSourceStat();
-    }
-
-    public JdbcSqlStat getSqlStatById(Integer id) {
-        init();
-
-        for (DruidDataSource ds : getDruidDataSourceInstances()) {
-            JdbcSqlStat sqlStat = ds.getDataSourceStat().getSqlStat(id);
-            if (sqlStat != null) return sqlStat;
-        }
-        return null;
-    }
-
-    public Map getDataSourceStatData(Integer id) {
-        if (id == null) {
-            return null;
-        }
-        DruidDataSource datasource = getDruidDataSourceById(id);
-        return datasource == null ? null : dataSourceToMapData(datasource);
-    }
-
-    public DruidDataSource getDruidDataSourceById(Integer identity) {
-        init();
-
-        if (identity == null) {
-            return null;
-        }
-
-        for (DruidDataSource datasource : getDruidDataSourceInstances()) {
-            if (System.identityHashCode(datasource) == identity) {
-                return datasource;
-            }
-        }
-        return null;
-    }
-
-    public Map getSqlStatData(Integer id) {
-        if (id == null) {
-            return null;
-        }
-        JdbcSqlStat sqlStat = getSqlStatById(id);
-        return sqlStat == null ? null : getSqlStatData(sqlStat);
-    }
-
-    public Map getSqlStatData(JdbcSqlStat sqlStat) {
-        try {
-            return sqlStat.getData();
-        } catch (JMException e) {
-        }
-        return null;
-    }
-
-    public List getDataSourceStatList() {
-        List datasourceList = new ArrayList();
-        for (DruidDataSource dataSource : getDruidDataSourceInstances()) {
-            datasourceList.add(dataSourceToMapData(dataSource));
-        }
-        return datasourceList;
-    }
-
-    public Map returnJSONBasicStat() {
-        Map dataMap = new LinkedHashMap();
-        dataMap.put("Version", VERSION.getVersionNumber());
-        dataMap.put("Drivers", getDriversData());
-        return dataMap;
-    }
-
-    private List getDriversData() {
-        List drivers = new ArrayList();
-        for (Enumeration e = DriverManager.getDrivers(); e.hasMoreElements();) {
-            Driver driver = e.nextElement();
-            drivers.add(driver.getClass().getName());
-        }
-        return drivers;
-    }
-
-    public List> getPoolingConnectionInfoByDataSourceId(Integer id) {
-        DruidDataSource datasource = getDruidDataSourceById(id);
-        if (datasource == null) return null;
-        return datasource.getPoolingConnectionInfo();
-    }
-
-    public List getActiveConnectionStackTraceByDataSourceId(Integer id) {
-        DruidDataSource datasource = getDruidDataSourceById(id);
-        if (datasource == null || !datasource.isRemoveAbandoned()) return null;
-
-        return datasource.getActiveConnectionStackTrace();
-    }
-
-    private Map dataSourceToMapData(DruidDataSource dataSource) {
-
-        Map dataMap = new LinkedHashMap();
-        dataMap.put("Identity", System.identityHashCode(dataSource));
-        dataMap.put("Name", dataSource.getName());
-        dataMap.put("DbType", dataSource.getDbType());
-        dataMap.put("DriverClassName", dataSource.getDriverClassName());
-
-        dataMap.put("URL", dataSource.getUrl());
-        dataMap.put("UserName", dataSource.getUsername());
-        dataMap.put("FilterClassNames", dataSource.getFilterClassNames());
-
-        dataMap.put("WaitThreadCount", dataSource.getWaitThreadCount());
-        dataMap.put("NotEmptyWaitCount", dataSource.getNotEmptyWaitCount());
-        dataMap.put("NotEmptyWaitMillis", dataSource.getNotEmptyWaitMillis());
-
-        dataMap.put("PoolingCount", dataSource.getPoolingCount());
-        dataMap.put("PoolingPeak", dataSource.getPoolingPeak());
-        dataMap.put("PoolingPeakTime",
-                    dataSource.getPoolingPeakTime() == null ? null : dataSource.getPoolingPeakTime().toString());
-
-        dataMap.put("ActiveCount", dataSource.getActiveCount());
-        dataMap.put("ActivePeak", dataSource.getActivePeak());
-        dataMap.put("ActivePeakTime",
-                    dataSource.getActivePeakTime() == null ? null : dataSource.getActivePeakTime().toString());
-
-        dataMap.put("InitialSize", dataSource.getInitialSize());
-        dataMap.put("MinIdle", dataSource.getMinIdle());
-        dataMap.put("MaxActive", dataSource.getMaxActive());
-
-        dataMap.put("QueryTimeout", dataSource.getQueryTimeout());
-        dataMap.put("TransactionQueryTimeout", dataSource.getTransactionQueryTimeout());
-        dataMap.put("LoginTimeout", dataSource.getLoginTimeout());
-        dataMap.put("ValidConnectionCheckerClassName", dataSource.getValidConnectionCheckerClassName());
-        dataMap.put("ExceptionSorterClassName", dataSource.getExceptionSorterClassName());
-
-        dataMap.put("TestOnBorrow", dataSource.isTestOnBorrow());
-        dataMap.put("TestOnReturn", dataSource.isTestOnReturn());
-        dataMap.put("TestWhileIdle", dataSource.isTestWhileIdle());
-
-        dataMap.put("DefaultAutoCommit", dataSource.isDefaultAutoCommit());
-        dataMap.put("DefaultReadOnly", dataSource.isDefaultAutoCommit());
-        dataMap.put("DefaultTransactionIsolation", dataSource.getDefaultTransactionIsolation());
-
-        dataMap.put("LogicConnectCount", dataSource.getConnectCount());
-        dataMap.put("LogicCloseCount", dataSource.getCloseCount());
-        dataMap.put("LogicConnectErrorCount", dataSource.getConnectErrorCount());
-
-        dataMap.put("PhysicalConnectCount", dataSource.getCreateCount());
-        dataMap.put("PhysicalCloseCount", dataSource.getDestroyCount());
-        dataMap.put("PhysicalConnectErrorCount", dataSource.getCreateErrorCount());
-
-        dataMap.put("ExecuteCount", dataSource.getExecuteCount());
-        dataMap.put("ErrorCount", dataSource.getErrorCount());
-        dataMap.put("CommitCount", dataSource.getCommitCount());
-        dataMap.put("RollbackCount", dataSource.getRollbackCount());
-
-        dataMap.put("PSCacheAccessCount", dataSource.getCachedPreparedStatementAccessCount());
-        dataMap.put("PSCacheHitCount", dataSource.getCachedPreparedStatementHitCount());
-        dataMap.put("PSCacheMissCount", dataSource.getCachedPreparedStatementMissCount());
-
-        dataMap.put("StartTransactionCount", dataSource.getStartTransactionCount());
-        dataMap.put("TransactionHistogram", dataSource.getTransactionHistogramValues());
-
-        dataMap.put("ConnectionHoldTimeHistogram",
-                    dataSource.getDataSourceStat().getConnectionHoldHistogram().toArray());
-        dataMap.put("RemoveAbandoned", dataSource.isRemoveAbandoned());
-
-        return dataMap;
-    }
+	public void resetAll() {
+		ctx.resetAll();
+	}
 }
diff --git a/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java b/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java
index f48d4dbbdf..901d495a4b 100644
--- a/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java
+++ b/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java
@@ -490,10 +490,14 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
 
                 // 25 - 29
                 "Histogram", //
-                "LastSlowParameters", "ResultSetHoldTime", "ExecuteAndResultSetHoldTime", "FetchRowCountHistogram",
+                "LastSlowParameters", // 
+                "ResultSetHoldTime", // 
+                "ExecuteAndResultSetHoldTime", // 
+                "FetchRowCountHistogram", //
 
                 // 30
-                "EffectedRowCountHistogram", "ExecuteAndResultHoldTimeHistogram"
+                "EffectedRowCountHistogram", // 
+                "ExecuteAndResultHoldTimeHistogram"
 
         //
         };
diff --git a/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java b/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java
index a8dffa6b9c..d5797d596e 100644
--- a/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java
+++ b/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java
@@ -1,19 +1,18 @@
 package com.alibaba.druid.support;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
-import com.alibaba.druid.pool.DruidDataSource;
 import com.alibaba.druid.stat.DruidStatManagerFacade;
-import com.alibaba.druid.stat.JdbcSqlStat;
 import com.alibaba.druid.util.MapComparator;
 import com.alibaba.druid.util.StringUtils;
 import com.alibaba.fastjson.JSON;
 
 /**
+ * 注意:避免直接调用Druid相关对象例如DruidDataSource等,相关调用要到DruidStatManagerFacade里用反射实现
+ * 
  * @author sandzhang
  */
 public class JSONDruidStatService {
@@ -96,16 +95,7 @@ public class JSONDruidStatService {
         if (page == null) page = DEFAULT_PAGE;
         if (perPageCount == null) perPageCount = DEFAULT_PER_PAGE_COUNT;
 
-        List> array = new ArrayList>();
-        for (DruidDataSource datasource : druidStatManager.getDruidDataSourceInstances()) {
-            for (JdbcSqlStat sqlStat : datasource.getDataSourceStat().getSqlStatMap().values()) {
-                if (sqlStat.getExecuteCount() == 0 && sqlStat.getRunningCount() == 0) {
-                    continue;
-                }
-
-                array.add(druidStatManager.getSqlStatData(sqlStat));
-            }
-        }
+        List> array = druidStatManager.getSqlStatDataList();
 
         // orderby
         if (orderBy != null && orderBy.trim().length() != 0) {
diff --git a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java
index 693dcf4e42..addaba62f1 100644
--- a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java
+++ b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java
@@ -4,23 +4,24 @@ import java.io.IOException;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.List;
+import java.util.Map;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import com.alibaba.druid.pool.DruidDataSource;
 import com.alibaba.druid.sql.SQLUtils;
 import com.alibaba.druid.sql.ast.SQLStatement;
 import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
 import com.alibaba.druid.stat.DruidStatManagerFacade;
-import com.alibaba.druid.stat.JdbcSqlStat;
 import com.alibaba.druid.support.JSONDruidStatService;
 import com.alibaba.druid.util.IOUtils;
 import com.alibaba.druid.util.StringUtils;
 
 /**
+ * 注意:避免直接调用Druid相关对象例如DruidDataSource等,相关调用要到DruidStatManagerFacade里用反射实现
+ * 
  * @author sandzhang
  */
 public class StatViewServlet extends HttpServlet {
@@ -76,22 +77,19 @@ public class StatViewServlet extends HttpServlet {
 
         if (path.startsWith("/connectionInfo-") && path.endsWith(".html")) {
             Integer id = StringUtils.subStringToInteger(path, "connectionInfo-", ".");
-            DruidDataSource datasource = druidStatManager.getDruidDataSourceById(id);
-            returnViewConnectionInfo(datasource, request, response);
+            returnViewConnectionInfo(id, request, response);
             return;
         }
 
         if (path.startsWith("/activeConnectionStackTrace-") && path.endsWith(".html")) {
             Integer id = StringUtils.subStringToInteger(path, "activeConnectionStackTrace-", ".");
-            DruidDataSource datasource = druidStatManager.getDruidDataSourceById(id);
-            returnViewActiveConnectionStackTrace(datasource, request, response);
+            returnViewActiveConnectionStackTrace(id, request, response);
             return;
         }
 
         if (path.startsWith("/sql-") && path.endsWith(".html")) {
             Integer id = StringUtils.subStringToInteger(path, "sql-", ".");
-            JdbcSqlStat sqlStat = druidStatManager.getSqlStatById(id);
-            returnViewSqlStat(sqlStat, response);
+            returnViewSqlStat(druidStatManager.getSqlStatData(id), response);
             return;
         }
 
@@ -99,63 +97,58 @@ public class StatViewServlet extends HttpServlet {
         returnResourceFile(path, response);
     }
 
-    private void returnViewActiveConnectionStackTrace(DruidDataSource datasource, HttpServletRequest request,
+    private void returnViewActiveConnectionStackTrace(Integer id, HttpServletRequest request,
                                                       HttpServletResponse response) throws IOException {
-        if (datasource == null) return;
-
-        if (!datasource.isRemoveAbandoned()) {
-            response.getWriter().print(mergeTemplatePage("ERROR", "require set removeAbandoned=true"));
-            return;
-        }
 
         String text = IOUtils.readFromResource(RESOURCE_PATH + "/activeConnectionStackTrace.html");
-        text = text.replaceAll("\\{datasourceId\\}", String.valueOf(System.identityHashCode(datasource)));
+        text = text.replaceAll("\\{datasourceId\\}", id.toString());
         response.getWriter().print(text);
     }
 
-    private void returnViewConnectionInfo(DruidDataSource datasource, HttpServletRequest request,
-                                          HttpServletResponse response) throws IOException {
-        if (datasource == null) return;
-
+    private void returnViewConnectionInfo(Integer id, HttpServletRequest request, HttpServletResponse response)
+                                                                                                               throws IOException {
         String text = IOUtils.readFromResource(RESOURCE_PATH + "/connectionInfo.html");
-        text = text.replaceAll("\\{datasourceId\\}", String.valueOf(System.identityHashCode(datasource)));
+        text = text.replaceAll("\\{datasourceId\\}", id.toString());
         response.getWriter().print(text);
     }
 
-    private void returnViewSqlStat(JdbcSqlStat sqlStat, HttpServletResponse response) throws IOException {
+    private void returnViewSqlStat(Map sqlStat, HttpServletResponse response) throws IOException {
         if (sqlStat == null) return;
 
         StringBuilder content = new StringBuilder();
 
-        content.append("

FULL SQL

" + sqlStat.getSql() + "

"); + content.append("

FULL SQL

" + sqlStat.get("SQL") + "

"); content.append("

Format View:

"); content.append("
"); content.append("

API:com.alibaba.druid.sql.SQLUtils.format(sql,DBType);

"); content.append("
"); - if (sqlStat.getLastSlowParameters() != null && sqlStat.getLastSlowParameters().trim().length() > 0) { + if (sqlStat.get("LastSlowParameters") != null + && sqlStat.get("LastSlowParameters").toString().trim().length() > 0) { content.append("

LastSlow SQL View:

"); content.append(""); content.append(""); content.append(""); - content.append(""); + content.append(""); content.append(""); content.append(""); content.append(""); - content.append(""); + content.append(""); content.append(""); content.append("
MaxTimespanOccurTime" + format.format(sqlStat.getExecuteNanoSpanMaxOccurTime()) + "" + format.format(sqlStat.get("MaxTimespanOccurTime")) + "
LastSlowParameters" + sqlStat.getLastSlowParameters() + "" + sqlStat.get("LastSlowParameters") + "
"); content.append("
"); } - - List statementList = SQLUtils.parseStatements(sqlStat.getSql(), sqlStat.getDbType()); + + List statementList = SQLUtils.parseStatements((String) sqlStat.get("SQL"), + (String) sqlStat.get("DbType")); + if (!statementList.isEmpty()) { content.append("

Parse View:

"); SQLStatement statemen = statementList.get(0); - SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(statementList, sqlStat.getDbType()); + SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(statementList, (String) sqlStat.get("DbType")); statemen.accept(visitor); content.append(""); content.append(""); diff --git a/src/main/java/com/alibaba/druid/util/ReflectionUtils.java b/src/main/java/com/alibaba/druid/util/ReflectionUtils.java index 49f979a65a..045313c4ec 100644 --- a/src/main/java/com/alibaba/druid/util/ReflectionUtils.java +++ b/src/main/java/com/alibaba/druid/util/ReflectionUtils.java @@ -4,21 +4,28 @@ import java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; + /** * @author sandzhang */ public class ReflectionUtils { + private final static Log LOG = LogFactory.getLog(ReflectionUtils.class); + public static Class getClassFromWebContainerOrCurrentClassLoader(String className) { Class result = null; try { result = HttpServletRequest.class.getClassLoader().loadClass(className); } catch (ClassNotFoundException e) { + if (LOG.isDebugEnabled()) LOG.debug("can'r find class in web container classLoader ", e); } if (result == null) { try { result = Thread.currentThread().getContextClassLoader().loadClass(className); } catch (ClassNotFoundException e) { + LOG.error("can'r find class in current thread context classLoader ", e); } } return result; @@ -30,16 +37,28 @@ public class ReflectionUtils { Method m = classObject.getMethod(methodName); return m.invoke(classObject); } catch (Exception e) { + LOG.warn("callStaticMethod fail:class=" + classObject.getName() + " method=" + methodName, e); return null; } } - public static String getTest() { - return "test"; + public static Object callObjectMethod(Object obj, String methodName, Object... methodParams) { + try { + Method m = obj.getClass().getMethod(methodName); + return m.invoke(obj, methodParams); + } catch (Exception e) { + LOG.warn("callObjectMethod fail:class=" + obj.getClass().getName() + " method=" + methodName, e); + return null; + } + } + + public void getTest() { + System.out.println("dd"); + // return "test"; } public static void main(String args[]) { - System.out.println(callStaticMethod(ReflectionUtils.class, "getTest")); + System.out.println(callObjectMethod(new ReflectionUtils(), "getTest")); } } diff --git a/src/main/java/com/alibaba/druid/util/StringUtils.java b/src/main/java/com/alibaba/druid/util/StringUtils.java index b1db53e68f..01ce45e10c 100644 --- a/src/main/java/com/alibaba/druid/util/StringUtils.java +++ b/src/main/java/com/alibaba/druid/util/StringUtils.java @@ -3,6 +3,8 @@ package com.alibaba.druid.util; import java.util.LinkedHashMap; import java.util.Map; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.fastjson.JSON; /** @@ -10,6 +12,8 @@ import com.alibaba.fastjson.JSON; */ public class StringUtils { + private final static Log LOG = LogFactory.getLog(StringUtils.class); + /** * Example: subString("12345","1","4")=23 * @@ -52,6 +56,7 @@ public class StringUtils { try { return Integer.parseInt(in); } catch (NumberFormatException e) { + LOG.warn("stringToInteger fail,string=" + in, e); return null; } } @@ -67,6 +72,7 @@ public class StringUtils { try { return Long.parseLong(in); } catch (NumberFormatException e) { + LOG.warn("stringToLong fail,string=" + in, e); return null; } } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/ClosedTest.java b/src/test/java/com/alibaba/druid/bvt/pool/ClosedTest.java new file mode 100644 index 0000000000..7dd6f43385 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/ClosedTest.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.pool; + +import java.sql.Connection; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.pool.DataSourceClosedException; +import com.alibaba.druid.pool.DruidDataSource; + +public class ClosedTest extends TestCase { + + public void test_close() throws Exception { + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + + Connection conn = dataSource.getConnection(); + conn.close(); + + dataSource.close(); + + DataSourceClosedException error = null; + + try { + dataSource.getConnection(); + } catch (DataSourceClosedException ex) { + error = ex; + } + + Assert.assertNotNull(error); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest.java b/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest.java index f87d99ddfb..f8ccfe8c9f 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest.java @@ -1,11 +1,13 @@ package com.alibaba.druid.bvt.pool; +import java.lang.reflect.Field; import java.sql.Connection; import junit.framework.Assert; import junit.framework.TestCase; import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.support.logging.Log; public class ConfigErrorTest extends TestCase { @@ -22,12 +24,17 @@ public class ConfigErrorTest extends TestCase { } public void test_connect() throws Exception { - DruidDataSource.LOG.resetStat(); - Assert.assertEquals(0, DruidDataSource.LOG.getErrorCount()); + Field field = DruidDataSource.class.getDeclaredField("LOG"); + field.setAccessible(true); + Log LOG = (Log) field.get(null); + + LOG.resetStat(); + + Assert.assertEquals(0, LOG.getErrorCount()); Connection conn = dataSource.getConnection(); conn.close(); - Assert.assertEquals(1, DruidDataSource.LOG.getErrorCount()); + Assert.assertEquals(1, LOG.getErrorCount()); } } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest2.java b/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest2.java index 4b7d4470cb..6b735aebeb 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest2.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest2.java @@ -1,11 +1,13 @@ package com.alibaba.druid.bvt.pool; +import java.lang.reflect.Field; import java.sql.Connection; import junit.framework.Assert; import junit.framework.TestCase; import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.support.logging.Log; public class ConfigErrorTest2 extends TestCase { @@ -24,12 +26,17 @@ public class ConfigErrorTest2 extends TestCase { } public void test_connect() throws Exception { - DruidDataSource.LOG.resetStat(); - Assert.assertEquals(0, DruidDataSource.LOG.getErrorCount()); + Field field = DruidDataSource.class.getDeclaredField("LOG"); + field.setAccessible(true); + Log LOG = (Log) field.get(null); + + LOG.resetStat(); + + Assert.assertEquals(0, LOG.getErrorCount()); Connection conn = dataSource.getConnection(); conn.close(); - Assert.assertEquals(1, DruidDataSource.LOG.getErrorCount()); + Assert.assertEquals(1, LOG.getErrorCount()); } } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest3.java b/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest3.java index 0a6a83a755..0bd5ee63d7 100644 --- a/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest3.java +++ b/src/test/java/com/alibaba/druid/bvt/pool/ConfigErrorTest3.java @@ -1,9 +1,12 @@ package com.alibaba.druid.bvt.pool; +import java.lang.reflect.Field; + import junit.framework.Assert; import junit.framework.TestCase; import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.support.logging.Log; public class ConfigErrorTest3 extends TestCase { @@ -24,9 +27,14 @@ public class ConfigErrorTest3 extends TestCase { } public void test_connect() throws Exception { - DruidDataSource.LOG.resetStat(); - Assert.assertEquals(0, DruidDataSource.LOG.getErrorCount()); + Field field = DruidDataSource.class.getDeclaredField("LOG"); + field.setAccessible(true); + Log LOG = (Log) field.get(null); + + LOG.resetStat(); + + Assert.assertEquals(0, LOG.getErrorCount()); dataSource.init(); - Assert.assertEquals(1, DruidDataSource.LOG.getErrorCount()); + Assert.assertEquals(1, LOG.getErrorCount()); } } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/SlowSqlMillisTest.java b/src/test/java/com/alibaba/druid/bvt/pool/SlowSqlMillisTest.java new file mode 100644 index 0000000000..227cd17197 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/SlowSqlMillisTest.java @@ -0,0 +1,32 @@ +package com.alibaba.druid.bvt.pool; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.filter.stat.StatFilter; +import com.alibaba.druid.pool.DruidDataSource; + + +public class SlowSqlMillisTest extends TestCase { + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + dataSource.setTestOnReturn(false); + dataSource.setTestWhileIdle(false); + dataSource.setConnectionProperties("druid.stat.slowSqlMillis=500"); + dataSource.setFilters("stat"); + dataSource.init(); + } + + protected void tearDown() throws Exception { + dataSource.close(); + } + + public void test_connect() throws Exception { + StatFilter filter = (StatFilter) dataSource.getProxyFilters().get(0); + Assert.assertEquals(500, filter.getSlowSqlMillis()); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/pool/SlowSqlMillisTest2.java b/src/test/java/com/alibaba/druid/bvt/pool/SlowSqlMillisTest2.java new file mode 100644 index 0000000000..0d3d8fdb18 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/SlowSqlMillisTest2.java @@ -0,0 +1,38 @@ +package com.alibaba.druid.bvt.pool; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.filter.stat.StatFilter; +import com.alibaba.druid.pool.DruidDataSource; + + +public class SlowSqlMillisTest2 extends TestCase { + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setTestOnBorrow(false); + dataSource.setTestOnReturn(false); + dataSource.setTestWhileIdle(false); + System.setProperty("druid.stat.slowSqlMillis", "500"); + dataSource.setFilters("stat"); + + { + StatFilter filter = (StatFilter) dataSource.getProxyFilters().get(0); + Assert.assertEquals(3000, filter.getSlowSqlMillis()); + } + dataSource.init(); + } + + protected void tearDown() throws Exception { + System.clearProperty("druid.stat.slowSqlMillis"); + dataSource.close(); + } + + public void test_connect() throws Exception { + StatFilter filter = (StatFilter) dataSource.getProxyFilters().get(0); + Assert.assertEquals(500, filter.getSlowSqlMillis()); + } +} diff --git a/test.html b/test.html new file mode 100644 index 0000000000..e69de29bb2 From e008c0b27b78a67a53923ba701d6fb133c68227a Mon Sep 17 00:00:00 2001 From: zhouhaibin <283595276@qq.com> Date: Fri, 10 Aug 2012 12:50:42 +0800 Subject: [PATCH 02/10] Merge remote-tracking branch 'zhb/master' Conflicts: src/main/java/com/alibaba/druid/support/http/StatViewServlet.java --- .../java/com/alibaba/druid/support/http/StatViewServlet.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java index addaba62f1..913fae5d31 100644 --- a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java +++ b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java @@ -144,6 +144,7 @@ public class StatViewServlet extends HttpServlet { List statementList = SQLUtils.parseStatements((String) sqlStat.get("SQL"), (String) sqlStat.get("DbType")); + if (!statementList.isEmpty()) { content.append("

Parse View:

"); From 5b687f894bdb937594342d9294a04fcac0871a0a Mon Sep 17 00:00:00 2001 From: zhouhaibin <283595276@qq.com> Date: Fri, 10 Aug 2012 13:00:02 +0800 Subject: [PATCH 03/10] modified: src/main/java/com/alibaba/druid/support/http/StatViewServlet.java --- pom.xml | 32 +++++++++---------- .../druid/support/http/StatViewServlet.java | 1 - 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index 9cf18e9825..696465cc14 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.alibaba druid - 0.2.6-SNAPSHOT + 0.2.7-SNAPSHOT jar druid @@ -213,7 +213,7 @@ - + javax.servlet @@ -252,18 +252,18 @@ true - org.mybatis - mybatis - 3.1.1 - provided - true + org.mybatis + mybatis + 3.1.1 + provided + true - org.mybatis - mybatis-spring - 1.1.1 - provided - true + org.mybatis + mybatis-spring + 1.1.1 + provided + true @@ -316,11 +316,11 @@ 11.2.0.3 provided --> - com.oracle - ojdbc14 - 10.2.0.2 - provided + com.oracle + ojdbc14 + 10.2.0.2.0 + com.microsoft.sqlserver sqljdbc4 diff --git a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java index 913fae5d31..addaba62f1 100644 --- a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java +++ b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java @@ -144,7 +144,6 @@ public class StatViewServlet extends HttpServlet { List statementList = SQLUtils.parseStatements((String) sqlStat.get("SQL"), (String) sqlStat.get("DbType")); - if (!statementList.isEmpty()) { content.append("

Parse View:

"); From 31dcc3c91b1b5c069503d8d5f20e69a7465b14b6 Mon Sep 17 00:00:00 2001 From: wenshao Date: Fri, 10 Aug 2012 15:03:03 +0800 Subject: [PATCH 04/10] fix pom.xml --- pom.xml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 696465cc14..6e3a3a52c4 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.alibaba druid - 0.2.7-SNAPSHOT + 0.2.6-SNAPSHOT jar druid @@ -316,9 +316,10 @@ 11.2.0.3 provided
--> - com.oracle - ojdbc14 - 10.2.0.2.0 + com.oracle + ojdbc14 + 10.2.0.2 + provided From 106bdf9af82b492f32594942512dd3de5d62a3ec Mon Sep 17 00:00:00 2001 From: wenshao Date: Fri, 10 Aug 2012 15:07:44 +0800 Subject: [PATCH 05/10] bug fixed for ReflectionUtils --- .../stat/DruidDataSourceStatJNDIStatStrategy.java | 12 +++++++++++- .../com/alibaba/druid/util/ReflectionUtils.java | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatJNDIStatStrategy.java b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatJNDIStatStrategy.java index d8026865f4..9d0091a603 100644 --- a/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatJNDIStatStrategy.java +++ b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatJNDIStatStrategy.java @@ -3,12 +3,22 @@ package com.alibaba.druid.stat; import java.util.List; import java.util.Map; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.druid.util.ReflectionUtils; public class DruidDataSourceStatJNDIStatStrategy implements DruidDataSourceStatStrategy{ + private final static Log LOG = LogFactory.getLog(DruidDataSourceStatJNDIStatStrategy.class); private Object getStrategyB() { - return ReflectionUtils.getClassFromWebContainerOrCurrentClassLoader("com.alibaba.druid.stat.DruidDataSourceStatDefaultStrategy"); + Class clazz = ReflectionUtils.getClassFromWebContainerOrCurrentClassLoader("com.alibaba.druid.stat.DruidDataSourceStatDefaultStrategy"); + Object object = null; + try { + object = clazz.newInstance(); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } + return object; } @SuppressWarnings("unchecked") diff --git a/src/main/java/com/alibaba/druid/util/ReflectionUtils.java b/src/main/java/com/alibaba/druid/util/ReflectionUtils.java index 045313c4ec..223a861cd6 100644 --- a/src/main/java/com/alibaba/druid/util/ReflectionUtils.java +++ b/src/main/java/com/alibaba/druid/util/ReflectionUtils.java @@ -42,10 +42,20 @@ public class ReflectionUtils { } } - public static Object callObjectMethod(Object obj, String methodName, Object... methodParams) { + public static Object callObjectMethod(Object obj, String methodName) { try { Method m = obj.getClass().getMethod(methodName); - return m.invoke(obj, methodParams); + return m.invoke(obj); + } catch (Exception e) { + LOG.warn("callObjectMethod fail:class=" + obj.getClass().getName() + " method=" + methodName, e); + return null; + } + } + + public static Object callObjectMethod(Object obj, String methodName, Integer id) { + try { + Method m = obj.getClass().getMethod(methodName, Integer.class); + return m.invoke(obj, id); } catch (Exception e) { LOG.warn("callObjectMethod fail:class=" + obj.getClass().getName() + " method=" + methodName, e); return null; From 48befaf00dc17de2e69089a63f3401922806fb0f Mon Sep 17 00:00:00 2001 From: zhouhaibin <283595276@qq.com> Date: Fri, 10 Aug 2012 15:08:51 +0800 Subject: [PATCH 06/10] Merge remote-tracking branch 'zhb/master' Conflicts: src/main/java/com/alibaba/druid/support/http/StatViewServlet.java --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 696465cc14..e8cfe02253 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.alibaba druid - 0.2.7-SNAPSHOT + 0.2.6-SNAPSHOT jar druid From 5cf58ff2b710f7379454d135815ccc7fc08db512 Mon Sep 17 00:00:00 2001 From: zhouhaibin <283595276@qq.com> Date: Fri, 10 Aug 2012 15:30:35 +0800 Subject: [PATCH 07/10] Merge remote-tracking branch 'zhb/master' Conflicts: src/main/java/com/alibaba/druid/support/http/StatViewServlet.java --- .../java/com/alibaba/druid/support/http/StatViewServlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java index addaba62f1..df9fb7b460 100644 --- a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java +++ b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java @@ -130,7 +130,7 @@ public class StatViewServlet extends HttpServlet { content.append("

LastSlow SQL View:

"); content.append("
"); content.append(""); - content.append(""); + content.append(""); content.append(""); content.append(""); content.append(""); From ed1fc448c315c06309c46d8d4977588f35f4bd78 Mon Sep 17 00:00:00 2001 From: wenshao Date: Fri, 10 Aug 2012 17:28:33 +0800 Subject: [PATCH 08/10] bug fixed SQLUtils.format --- .../java/com/alibaba/druid/sql/SQLUtils.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/alibaba/druid/sql/SQLUtils.java b/src/main/java/com/alibaba/druid/sql/SQLUtils.java index 630dca4658..a05d04f77d 100644 --- a/src/main/java/com/alibaba/druid/sql/SQLUtils.java +++ b/src/main/java/com/alibaba/druid/sql/SQLUtils.java @@ -16,14 +16,18 @@ import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerOutputVisitor; import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerSchemaStatVisitor; import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLExprParser; +import com.alibaba.druid.sql.parser.SQLParseException; import com.alibaba.druid.sql.parser.SQLParserUtils; import com.alibaba.druid.sql.parser.SQLStatementParser; import com.alibaba.druid.sql.parser.Token; import com.alibaba.druid.sql.visitor.SQLASTOutputVisitor; import com.alibaba.druid.sql.visitor.SchemaStatVisitor; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.druid.util.JdbcUtils; public class SQLUtils { + private final static Log LOG = LogFactory.getLog(SQLUtils.class); public static String toSQLString(SQLObject sqlObject, String dbType) { if (JdbcUtils.MYSQL.equals(dbType)) { @@ -118,16 +122,22 @@ public class SQLUtils { } public static String format(String sql, String dbType) { - List statementList = toStatementList(sql, dbType); + try { + List statementList = toStatementList(sql, dbType); - StringBuilder out = new StringBuilder(); - SQLASTOutputVisitor visitor = createFormatOutputVisitor(out, statementList, dbType); + StringBuilder out = new StringBuilder(); + SQLASTOutputVisitor visitor = createFormatOutputVisitor(out, statementList, dbType); - for (SQLStatement stmt : statementList) { - stmt.accept(visitor); + for (SQLStatement stmt : statementList) { + stmt.accept(visitor); + } + + return out.toString(); + } catch (SQLParseException ex) { + LOG.warn("format error", ex); + + return sql; } - - return out.toString(); } public static SQLASTOutputVisitor createFormatOutputVisitor(Appendable out, List statementList, From 1d0fac6d9c20e9e172ec4c50f2eb5d7fc193076b Mon Sep 17 00:00:00 2001 From: Zhanming Qi Date: Fri, 10 Aug 2012 19:21:35 +0800 Subject: [PATCH 09/10] delete test.html --- test.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test.html diff --git a/test.html b/test.html deleted file mode 100644 index e69de29bb2..0000000000 From a33629fa1ccc712160524ba3d787c12d8cfa00b7 Mon Sep 17 00:00:00 2001 From: wenshao Date: Fri, 10 Aug 2012 19:48:57 +0800 Subject: [PATCH 10/10] StatFilter support logSlowSql --- .../com/alibaba/druid/filter/stat/StatFilter.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java b/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java index 615097cdff..0e88e16577 100644 --- a/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java +++ b/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java @@ -81,6 +81,8 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean { // 3 seconds is slow sql protected long slowSqlMillis = 3 * 1000; + protected boolean logSlowSql = false; + private String dbType; private boolean mergeSql = false; @@ -182,6 +184,15 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean { } } } + + { + String property = properties.getProperty("druid.stat.logSlowSql"); + if ("true".equals(property)) { + this.logSlowSql = true; + } else if ("false".equals(property)) { + this.logSlowSql = false; + } + } } @Override @@ -507,6 +518,10 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean { } buf.append(']'); sqlStat.setLastSlowParameters(buf.toString()); + + if (logSlowSql) { + LOG.error("slow sql " + millis + " millis. \n" + statement.getLastExecuteSql() + "\n" + buf.toString()); + } } } }
MaxTimespanOccurTimeSlowestSqlOccurTime" + format.format(sqlStat.get("MaxTimespanOccurTime")) + "