[英]DBCP - PSQL Exception - Connection Pool
我的单元测试有问题。 我试图实现一些单元测试来检查数据库请求(插入,更新,解析,绑定,执行...)。
事情是我得到以下异常:
PSQLException:此连接已关闭。
我的代码:
DataSource类可以在不同的类中使用相同的连接
public class DataSource {
private static DataSource datasource;
private BasicDataSource ds;
private DataSource() throws IOException, SQLException, PropertyVetoException {
ds = new BasicDataSource();
ds.setDriverClassName("org.postgresql.Driver");
ds.setUsername("postgres");
ds.setPassword("postgres");
ds.setUrl("jdbc:postgresql://localhost:5432/ehealth");
// the settings below are optional -- dbcp can work with defaults
// ds.setMinIdle(5);
// ds.setMaxIdle(20);
// ds.setMaxOpenPreparedStatements(180);
}
public static DataSource getInstance() throws IOException, SQLException, PropertyVetoException {
if (datasource == null) {
datasource = new DataSource();
return datasource;
} else {
return datasource;
}
}
public Connection getConnection() throws SQLException {
return this.ds.getConnection();
}
}
我的静态方法返回<String, List<PreparedStatement>>
的映射
public static Map<String, List<PreparedStatement>> test(int numberOfRequest) throws SQLException{
try(Connection con = getHealthConnection(); Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);){
Map<String, List<PreparedStatement>> myMap = new HashMap<String, List<PreparedStatement>>();
List<PreparedStatement> lstPreparedStmt = new ArrayList<PreparedStatement>();
String request = "INSERT INTO PATIENT VALUES (?, ?, ?, ?, 'M', 'OTHER')";
myMap.put(request, null);
int counter = 0;
String rqstSelect = "SELECT * FROM patient ORDER BY pat_id"; //initialize SELECT request
ResultSet resRequest = stmt.executeQuery(rqstSelect); //execute SELECT
String newId = createNewIdByIncrement(resRequest); //initialize first new id
while(counter < numberOfRequest){
String newName = generateRandomString(); //generate random new name
String newLast = generateRandomString(); //generate random new last name
String newLast2 = generateRandomString(); //generate random new last name 2
PreparedStatement prep = con.prepareStatement(request, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);
prep.setString(1, newId);
prep.setString(2, newName);
prep.setString(3, newLast);
prep.setString(4, newLast2);
lstPreparedStmt.add(prep);
counter = counter + 1; //increment counter
int newIdAsInt = Integer.parseInt(newId) + 1; //increment id
newId = concatenationZeroIntAsString(newIdAsInt, 8);
}
myMap.put(request, lstPreparedStmt);
return myMap;
}
}
最后,由我的@Test调用的方法与以前的方法共享相同的连接
private void insertPreparedStatementRequest(int numberOfRequest) throws SQLException, IOException, PropertyVetoException{
try(Connection con = DataSource.getInstance().getConnection(); Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY,
ResultSet.HOLD_CURSORS_OVER_COMMIT);){
// check number of row before insert
String rqstCountRowBefore = "SELECT * FROM patient ORDER BY pat_id";
ResultSet resCheckBefore = stmt.executeQuery(rqstCountRowBefore);
int rowBefore = TestUtils.getRowCount(resCheckBefore);
Assert.assertNotNull("Request's result is null", resCheckBefore);
// insert X row
Map<String, List<PreparedStatement>> allRequest = TestUtils.test(numberOfRequest);
for(Map.Entry<String, List<PreparedStatement>> e : allRequest.entrySet()){
List<PreparedStatement> lstStatement = e.getValue();
Iterator<PreparedStatement> valIterator = lstStatement.iterator();
while(valIterator.hasNext()){
valIterator.next().execute();
}
}
// check number of row after insert
String rqstCountrowAfter = "SELECT * FROM patient ORDER BY pat_id";
ResultSet resCheckAfter = stmt.executeQuery(rqstCountrowAfter);
int rowAfter = TestUtils.getRowCount(resCheckAfter);
Assert.assertNotNull("Request's result is null", resCheckBefore);
Assert.assertEquals("Insert result's request unsuccesfull", rowBefore + numberOfRequest, rowAfter);
}
}
我不明白为什么我的连接似乎已关闭。 我需要在后一种方法中获得与第一种方法相同的连接。 问题是我创建了一个DataSource来使用在第一种方法中已经创建的连接。
错误来自以下行: valIterator.next().execute()
日志:
org.postgresql.util.PSQLException: This connection has been closed.
at org.postgresql.jdbc2.AbstractJdbc2Connection.checkClosed(AbstractJdbc2Connection.java:714)
at org.postgresql.jdbc2.AbstractJdbc2Connection.getAutoCommit(AbstractJdbc2Connection.java:680)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:507)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:388)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:381)
at eu.clarussecure.proxy.protocol.plugins.pgsql.Scenarii.insertPreparedStatementRequest(Scenarii.java:191)
at eu.clarussecure.proxy.protocol.plugins.pgsql.Scenarii.insertPreparedStmtPatientRow5(Scenarii.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
PreparedStatement
是特定Connection
上下文中的资源。 在test
方法中,您已经通过Connection con = getHealthConnection();
创建了准备好的语句Connection con = getHealthConnection();
然后退出方法test
。
退出test
方法将使连接返回到池中或将其关闭,但最终您将无法获得相同的Connection
对象,除非您在Connection
上实现了singleton,否则您不太可能在调用test
后关闭针对其创建了语句的Connection
完成。
在您的insertPreparedStatementRequest
方法中,您正在创建一个新的Connection
并且该连接对象与准备了这些语句的连接对象无关,因此会产生错误。
只要这些语句的基础连接仍然存在,就需要执行这些准备好的语句。 为此,您需要将Connection从insertPreparedStatementRequest
传递到test
方法,即,需要将Connection
置于test
方法的外部。
希望能帮助到你 !!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.