繁体   English   中英

DBCP-PSQL异常-连接池

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM