From 1d7bc65b3d8f3d5dbaca7e45a8b1b9d78ed2a104 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Fri, 24 Feb 2017 00:05:34 +0800 Subject: [PATCH 1/4] remove the statement from pool while it threw an exception MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While the pooled PreparedStatement threw an exception, remove it from the pool, and then close it. The commit 94638ad didn’t fix issue #1498 . Try this one. --- .../com/alibaba/druid/pool/DruidPooledConnection.java | 6 ++++++ .../com/alibaba/druid/pool/PreparedStatementPool.java | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java b/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java index 2f95d12309..c4761d7f92 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java +++ b/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java @@ -173,6 +173,12 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql. stmt.getPreparedStatementHolder().setFetchRowPeak(stmt.getFetchRowPeak()); stmt.setClosed(true); // soft set close + } else if (stmt.isPooled() && holder.isPoolPreparedStatements()) { + // the PreparedStatement threw an exception + stmt.clearResultSet(); + holder.removeTrace(stmt); + + holder.getStatementPool().remove(stmt.getPreparedStatementHolder()); } else { try { //Connection behind the statement may be in invalid state, which will throw a SQLException. diff --git a/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java b/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java index d6f64ebc18..03d556fab4 100644 --- a/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java +++ b/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java @@ -72,6 +72,14 @@ public class PreparedStatementPool { return holder; } + public void remove(PreparedStatementHolder stmtHolder) throws SQLException { + if (stmtHolder == null) { + return; + } + map.remove(stmtHolder.key, stmtHolder); + closeRemovedStatement(stmtHolder); + } + public void put(PreparedStatementHolder stmtHolder) throws SQLException { PreparedStatement stmt = stmtHolder.statement; From 22c8b9b67b4aa973443b38c64261a607f7128d5e Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Fri, 24 Feb 2017 17:21:14 +0800 Subject: [PATCH 2/4] Downgrade to JDK6. remove(Object, Object) is not existed in HashMap of JDK6. --- src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java b/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java index 03d556fab4..d5c3d0b994 100644 --- a/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java +++ b/src/main/java/com/alibaba/druid/pool/PreparedStatementPool.java @@ -76,7 +76,7 @@ public class PreparedStatementPool { if (stmtHolder == null) { return; } - map.remove(stmtHolder.key, stmtHolder); + map.remove(stmtHolder.key); closeRemovedStatement(stmtHolder); } From 463ffc49a258979a274103285ae1f7dbce2c6d43 Mon Sep 17 00:00:00 2001 From: DigitalSonic Date: Sat, 25 Feb 2017 00:24:04 +0800 Subject: [PATCH 3/4] add test case add a test case for DruidPooledConnection.closePoolableStatement() method --- .../pool/ClosePoolableStatementTest.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/test/java/com/alibaba/druid/pool/ClosePoolableStatementTest.java diff --git a/src/test/java/com/alibaba/druid/pool/ClosePoolableStatementTest.java b/src/test/java/com/alibaba/druid/pool/ClosePoolableStatementTest.java new file mode 100644 index 0000000000..8a9c39ed73 --- /dev/null +++ b/src/test/java/com/alibaba/druid/pool/ClosePoolableStatementTest.java @@ -0,0 +1,76 @@ +package com.alibaba.druid.pool; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementSetter; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * 测试开启PSCache后关闭DruidPooledPreparedStatement时的情况 + * + * @author DigitalSonic + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:com/alibaba/druid/pool/dataSource.xml") +public class ClosePoolableStatementTest { + @Autowired + private DruidDataSource dataSource; + + private JdbcTemplate jdbcTemplate; + + @Before + public void setUp() throws Exception { + dataSource.setPoolPreparedStatements(true); + dataSource.setMaxPoolPreparedStatementPerConnectionSize(5); + dataSource.init(); + + jdbcTemplate = new JdbcTemplate(dataSource); + jdbcTemplate.execute("create table test (id int, val varchar(32), primary key (id))"); + } + + @After + public void tearDown() throws Exception { + jdbcTemplate.execute("drop table test"); + } + + /** + * 关注抛出异常后能否正确将PreparedStatement移出缓存,能正常执行后续SQL + */ + @Test + public void testClose() throws Exception { + insertData(1, "a"); + try { + insertData(1, "a"); + } catch (Exception e) { + assertTrue(e instanceof DuplicateKeyException); + } + try { + insertData(1, "a"); + } catch (Exception e) { + assertTrue(e instanceof DuplicateKeyException); + assertEquals(-1, e.getMessage().indexOf("closed")); + } + } + + private void insertData(final int id, final String val) { + jdbcTemplate.update("insert into test (id, val) values (?, ?)", new PreparedStatementSetter() { + @Override + public void setValues(PreparedStatement ps) throws SQLException { + ps.setInt(1, id); + ps.setString(2, val); + } + }); + } +} From d86d6cbcfe8809c2bc59d7e946453c305b136be2 Mon Sep 17 00:00:00 2001 From: lixiaohao Date: Mon, 6 Mar 2017 12:14:52 +0800 Subject: [PATCH 4/4] Update license year range to 2017 Update license year range to 2017 --- license.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/license.txt b/license.txt index 8deeff6746..00b845b43b 100644 --- a/license.txt +++ b/license.txt @@ -1,4 +1,4 @@ -Copyright 1999-2016 Alibaba Group Holding Ltd. +Copyright 1999-2017 Alibaba Group Holding Ltd. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.