【发布时间】:2017-04-19 23:49:42
【问题描述】:
我的单元测试有问题。我正在尝试实现一些单元测试来检查数据库请求(插入、更新、解析、绑定、执行......)。
事情是我得到以下异常:
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)
【问题讨论】:
-
每次测试后如何清理数据库中的数据? createNewIdByIncrement() 函数究竟做了什么?
-
实际上没有办法在测试后清理数据库。我稍后会编码(不知道如何)。我的客户已经得到了一个数据库,我正在研究它。如果他将 id 列设置为自动增量,他现在不会。然后,以防万一,我已经实现了设置 Id 的方法(以实现我的测试),即使我确定它会自动递增
-
盲注:createNewIdByIncrement() 在每次运行时创建相同的 Id,但您的表已经将这些值作为主键。 INSERT 失败,try(Connection con = ...) { ... } 关闭连接。然后您会看到连接在其他地方关闭,但它与明显的故障点无关,因为连接之前已关闭。
-
我在其他几个测试中使用 createNewIdByIncrement() 并且工作正常。不要这么想,这就是问题所在。我试图只创建一种方法并将所有方法 test() 代码放在 insertPreparedStatement() 方法中。一切都运作良好。然后问题来自连接。我需要创建一个连接池(我相信)。我不知道如何将 Name 配置为 bind() 和 lookup() 我的数据源。我正在使用 Postgres,我可能需要创建一个属性文件......我是连接池的初学者
标签: java postgresql unit-testing jdbc connection-pooling