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 de90784300..3617687d62 100644 --- a/src/main/java/com/alibaba/druid/filter/logging/LogFilter.java +++ b/src/main/java/com/alibaba/druid/filter/logging/LogFilter.java @@ -683,7 +683,7 @@ public abstract class LogFilter extends FilterEventAdapter implements LogFilterM throws SQLException { statementLog("{conn-" + statement.getConnectionProxy().getId() + ", pstmt-" + statement.getId() - + "} clearParameters. " + statement.getSql()); + + "} clearParameters. "); chain.preparedStatement_clearParameters(statement); } diff --git a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java index c52f27a26a..22f01cf859 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidDataSource.java @@ -770,7 +770,14 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat for (int i = 0; i < poolingCount; ++i) { try { - JdbcUtils.close(connections[i].getConnection()); + ConnectionHolder connHolder = connections[i]; + + for (PreparedStatementHolder stmtHolder : connHolder.getStatementPool().getMap().values()) { + connHolder.getStatementPool().closeRemovedStatement(stmtHolder); + } + connHolder.getStatementPool().getMap().clear(); + + JdbcUtils.close(connHolder.getConnection()); connections[i] = null; destroyCount++; } catch (Exception ex) { diff --git a/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java b/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java index 1aa893d71b..198400a159 100644 --- a/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java +++ b/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java @@ -23,6 +23,8 @@ import java.util.Map; import java.util.Map.Entry; import com.alibaba.druid.pool.DruidPooledPreparedStatement.PreparedStatementKey; +import com.alibaba.druid.proxy.jdbc.CallableStatementProxy; +import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy; import com.alibaba.druid.support.logging.Log; import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.druid.util.OracleUtils; @@ -89,7 +91,7 @@ public class PreparedStatementPool { PreparedStatementHolder oldHolder = map.put(key, holder); if (oldHolder != null && oldHolder != holder) { oldHolder.setPooling(false); - dataSource.closePreapredStatement(oldHolder); + closeRemovedStatement(oldHolder); } else { if (holder.getHitCount() == 0) { dataSource.incrementCachedPreparedStatementCount(); @@ -97,6 +99,22 @@ public class PreparedStatementPool { } holder.setPooling(true); + + if (LOG.isDebugEnabled()) { + String message = null; + if (holder.getStatement() instanceof PreparedStatementProxy) { + PreparedStatementProxy stmtProxy = (PreparedStatementProxy) holder.getStatement(); + if (stmtProxy instanceof CallableStatementProxy) { + message = "{conn-" + stmtProxy.getConnectionProxy().getId() + ", cstmt-" + stmtProxy.getId() + "} enter cache"; + } else { + message = "{conn-" + stmtProxy.getConnectionProxy().getId() + ", pstmt-" + stmtProxy.getId() + "} enter cache"; + } + } else { + message = "stmt enter cache"; + } + + LOG.debug(message); + } } public void clear() throws SQLException { @@ -110,7 +128,23 @@ public class PreparedStatementPool { } } - private void closeRemovedStatement(PreparedStatementHolder holder) throws SQLException { + public void closeRemovedStatement(PreparedStatementHolder holder) throws SQLException { + if (LOG.isDebugEnabled()) { + String message = null; + if (holder.getStatement() instanceof PreparedStatementProxy) { + PreparedStatementProxy stmtProxy = (PreparedStatementProxy) holder.getStatement(); + if (stmtProxy instanceof CallableStatementProxy) { + message = "{conn-" + stmtProxy.getConnectionProxy().getId() + ", cstmt-" + stmtProxy.getId() + "} exit cache"; + } else { + message = "{conn-" + stmtProxy.getConnectionProxy().getId() + ", pstmt-" + stmtProxy.getId() + "} exit cache"; + } + } else { + message = "stmt exit cache"; + } + + LOG.debug(message); + } + holder.setPooling(false); if (holder.isInUse()) { return; diff --git a/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java b/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java index 687a9a7e6f..d0e04f2aaf 100644 --- a/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java +++ b/src/main/java/com/alibaba/druid/support/http/WebStatFilter.java @@ -11,6 +11,7 @@ import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @@ -32,6 +33,8 @@ public class WebStatFilter implements Filter { public final static String PARAM_NAME_SESSION_STAT_ENABLE = "sessionStatEnable"; public final static String PARAM_NAME_SESSION_STAT_MAX_COUNT = "sessionStatMaxCount"; public static final String PARAM_NAME_EXCLUSIONS = "exclusions"; + public static final String PARAM_NAME_PRINCIPAL_SESSION_NAME = "princialSessionName"; + public static final String PARAM_NAME_PRINCIPAL_COOKIE_NAME = "princialCookieName"; public final static int DEFAULT_MAX_STAT_SESSION_COUNT = 1000 * 100; @@ -52,6 +55,9 @@ public class WebStatFilter implements Filter { private String contextPath; + private String principalSessionName; + private String principalCookieName; + @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { @@ -102,12 +108,15 @@ public class WebStatFilter implements Filter { if (sessionStat != null) { sessionStat.afterInvoke(error, nanoSpan); + sessionStat.setPrincipal(getPrincipal(httpRequest)); } else { sessionStat = getSessionStat(httpRequest); if (sessionStat != null) { sessionStat.setLastAccessTimeMillis(startMillis); sessionStat.reacord(nanoSpan); sessionStat.incrementRequestCount(); + + sessionStat.setPrincipal(getPrincipal(httpRequest)); } } @@ -162,6 +171,33 @@ public class WebStatFilter implements Filter { return sessionId; } + public String getPrincipal(HttpServletRequest httpRequest) { + if (principalSessionName != null) { + HttpSession session = httpRequest.getSession(createSession); + if (session == null) { + return null; + } + + Object sessionValue = session.getAttribute(principalSessionName); + + if (sessionValue == null) { + return null; + } + + return sessionValue.toString(); + } + + if (principalCookieName != null) { + for (Cookie cookie : httpRequest.getCookies()) { + if (principalCookieName.equals(cookie.getName())) { + return cookie.getValue(); + } + } + } + + return null; + } + public boolean isExclusion(String requestURI) { if (excludesPattern == null) { return false; @@ -187,6 +223,14 @@ public class WebStatFilter implements Filter { return request.getRequestURI(); } + public String getPrincipalSessionName() { + return principalSessionName; + } + + public String getPrincipalCookieName() { + return principalCookieName; + } + @Override public void init(FilterConfig config) throws ServletException { { @@ -195,6 +239,27 @@ public class WebStatFilter implements Filter { excludesPattern = new HashSet(Arrays.asList(exclusions.split("\\s*,\\s*"))); } } + + { + String param = config.getInitParameter(PARAM_NAME_PRINCIPAL_SESSION_NAME); + if (param != null) { + param = param.trim(); + if (param.length() != 0) { + this.principalSessionName = param; + } + } + } + + { + String param = config.getInitParameter(PARAM_NAME_PRINCIPAL_COOKIE_NAME); + if (param != null) { + param = param.trim(); + if (param.length() != 0) { + this.principalCookieName = param; + } + } + } + { String param = config.getInitParameter(PARAM_NAME_SESSION_STAT_ENABLE); if (param != null && param.trim().length() != 0) { diff --git a/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest4.java b/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest4.java new file mode 100644 index 0000000000..1a86ab1fc7 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/PSCacheTest4.java @@ -0,0 +1,135 @@ +package com.alibaba.druid.bvt.pool; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.TestForZY.A; +import com.alibaba.druid.pool.ConnectionHolder; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.DruidPooledConnection; +import com.alibaba.druid.pool.DruidPooledPreparedStatement; +import com.alibaba.druid.pool.DruidPooledResultSet; +import com.alibaba.druid.pool.PreparedStatementHolder; +import com.alibaba.druid.pool.PreparedStatementPool; +import com.alibaba.druid.util.JdbcUtils; + +public class PSCacheTest4 extends TestCase { + + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:x1"); + dataSource.setPoolPreparedStatements(true); + dataSource.setMaxOpenPreparedStatements(50); + dataSource.setFilters("log4j"); + } + + protected void tearDown() throws Exception { + JdbcUtils.close(dataSource); + } + + public void test_pscache() throws Exception { + DruidPooledConnection conn = dataSource.getConnection(); + + ConnectionHolder holder = conn.getConnectionHolder(); + PreparedStatementPool stmtPool = holder.getStatementPool(); + + final String sql_0 = "select 0"; + final String sql_1 = "select 1"; + + Assert.assertEquals(0, stmtPool.size()); + + PreparedStatementHolder stmtHoler_0; + PreparedStatementHolder stmtHoler_1_A; + PreparedStatementHolder stmtHoler_1_B; + PreparedStatementHolder stmtHoler_1_C; + + DruidPooledPreparedStatement stmt_0; + DruidPooledPreparedStatement stmt_1_A; + DruidPooledPreparedStatement stmt_1_B; + DruidPooledPreparedStatement stmt_1_C; + DruidPooledPreparedStatement stmt_1_D; + DruidPooledPreparedStatement stmt_1_E; + DruidPooledPreparedStatement stmt_1_F; + DruidPooledPreparedStatement stmt_1_G; + DruidPooledPreparedStatement stmt_1_H; + + DruidPooledResultSet rs_0; + DruidPooledResultSet rs_1_A; + DruidPooledResultSet rs_1_B; + DruidPooledResultSet rs_1_C; + DruidPooledResultSet rs_1_D; + DruidPooledResultSet rs_1_E; + DruidPooledResultSet rs_1_F; + DruidPooledResultSet rs_1_G; + DruidPooledResultSet rs_1_H; + + stmt_0 = (DruidPooledPreparedStatement) conn.prepareStatement(sql_0); + rs_0 = (DruidPooledResultSet) stmt_0.executeQuery(); + + Assert.assertTrue(stmt_0.getPreparedStatementHolder().isInUse()); + + stmt_1_A = (DruidPooledPreparedStatement) conn.prepareStatement(sql_1); + rs_1_A = (DruidPooledResultSet) stmt_1_A.executeQuery(); + + Assert.assertTrue(stmt_0.getPreparedStatementHolder().isInUse()); + Assert.assertTrue(stmt_1_A.getPreparedStatementHolder().isInUse()); + + stmt_1_B = (DruidPooledPreparedStatement) conn.prepareStatement(sql_1); + rs_1_B = (DruidPooledResultSet) stmt_1_B.executeQuery(); + rs_1_B.close(); + stmt_1_B.close(); + + Assert.assertTrue(stmt_0.getPreparedStatementHolder().isInUse()); + Assert.assertTrue(stmt_1_A.getPreparedStatementHolder().isInUse()); + Assert.assertFalse(stmt_1_B.getPreparedStatementHolder().isInUse()); + + stmt_1_C = (DruidPooledPreparedStatement) conn.prepareStatement(sql_1); + rs_1_C = (DruidPooledResultSet) stmt_1_C.executeQuery(); + rs_1_C.close(); + stmt_1_C.close(); + + Assert.assertTrue(stmt_0.getPreparedStatementHolder().isInUse()); + Assert.assertTrue(stmt_1_A.getPreparedStatementHolder().isInUse()); + Assert.assertFalse(stmt_1_B.getPreparedStatementHolder().isInUse()); + Assert.assertFalse(stmt_1_C.getPreparedStatementHolder().isInUse()); + + stmt_1_D = (DruidPooledPreparedStatement) conn.prepareStatement(sql_1); + rs_1_D = (DruidPooledResultSet) stmt_1_D.executeQuery(); + rs_1_D.close(); + stmt_1_D.close(); + + Assert.assertTrue(stmt_0.getPreparedStatementHolder().isInUse()); + Assert.assertTrue(stmt_1_A.getPreparedStatementHolder().isInUse()); + Assert.assertFalse(stmt_1_B.getPreparedStatementHolder().isInUse()); + Assert.assertFalse(stmt_1_C.getPreparedStatementHolder().isInUse()); + Assert.assertFalse(stmt_1_D.getPreparedStatementHolder().isInUse()); + + stmt_1_E = (DruidPooledPreparedStatement) conn.prepareStatement(sql_1); + rs_1_E = (DruidPooledResultSet) stmt_1_E.executeQuery(); + rs_1_E.close(); + stmt_1_E.close(); + + rs_1_A.close(); + stmt_1_A.close(); + + stmt_1_F = (DruidPooledPreparedStatement) conn.prepareStatement(sql_1); + rs_1_F = (DruidPooledResultSet) stmt_1_F.executeQuery(); + rs_1_F.close(); + stmt_1_F.close(); + + stmt_1_G = (DruidPooledPreparedStatement) conn.prepareStatement(sql_1); + rs_1_G = (DruidPooledResultSet) stmt_1_G.executeQuery(); + + stmt_1_H = (DruidPooledPreparedStatement) conn.prepareStatement(sql_1); + rs_1_H = (DruidPooledResultSet) stmt_1_H.executeQuery(); + rs_1_H.close(); + stmt_1_H.close(); + + rs_1_G.close(); + stmt_1_G.close(); + + conn.close(); + } +}