JDBC不需要的语句关闭

时间:2009-07-29 11:57:10

标签: java jdbc multithreading

我有一个Java JDBC应用程序,它使用多个线程从Oracle数据库中检索信息。每个线程都应该定期执行一个在特定表上执行select的语句(每个表的表都不同)。

线程是扩展Thread类的类的实例。此类有一个私有变量,用于存储与数据库的连接。该线程还有一个子线程,它通过语句定期从表中删除一些信息。

当我运行单个线程(从单个表中获取数据)时,它运行正常,但是当我运行多个线程(尝试从多个表中获取数据)时,我收到一条错误,指出我的语句在打印之前已关闭该语句生成的整个结果集。

我的问题是:

为什么一个不同的线程关闭了我的陈述? 为什么子线程没有关闭父线程语句? 我该怎么做才能防止这种情况发生?

我希望有人可以提供帮助。 顿

我不使用连接池,因为每个线程上的连接永久打开,因为我每20毫秒执行一次select语句,并且cild线程(有自己的连接)每10秒执行一次删除语句。

我无法将数据存储在数组中,因为当我检索它时,我必须发送它以进行处理。

我无法理解。每个线程都是一个不同的实例(具有不同的参数,除了那些用于连接又名用户,密码的那个)(类中没有任何静态),但却相互关闭。

每个线程都有自己的连接对象,它有自己的语句和结果集对象。它应该是线程安全的

这是一个代码示例

stmt = conn.createStatement();
rs = stmt.executeQuery(query);
while (rs.next()) {
//some processing
}
stmt.close();

conn变量是一个连接,是在thrad的构造函数中创建的,这可能是问题吗?

新编辑

我已将我的连接对象包装在一个包装类中,并将其扩展为两个不同的连接包装类,一个由执行select语句的线程使用,另一个由执行delete语句的线程使用。 我在声明之后没有关闭我的连接,因为它效率低下,但我确实关闭了声明 我没有线程之间的任何共享对象,因为我不需要任何。每个线程使用不同的语句对象和不同的结果集从不同的表中选择数据,并将其传递给API。 使用连接池会重新考虑我的整个应用程序,但如果没有其他解决方案,那么我将不得不这样做。

感谢您的帮助和对不起,如果我听起来很困难,抱歉从一开始就没有更清楚地表达自己

2 个答案:

答案 0 :(得分:3)

如果确保不在线程之间共享状态,则无需担心同步。

     
  1. 使用连接池。在执行每个数据库语句之前,从池中检索连接。即使您每秒50次获取和释放连接,池中也将保持与数据库的连接,并且只有在多个线程同时需要数据库连接时才需要新连接。我建议你看看DBCP,它有一个强大的,线程安全且灵活的数据库连接池的良好实现。
  2.  
  3. 使用局部变量以确保连接范围意味着它只对当前线程可见。
  4.  完成数据库语句执行后,
  5. 始终关闭连接(或将它们释放回池中)。在JDBC代码周围使用finally块来执行此操作。
  6.  
  7. 再次创建语句时,请确保它们是本地语句,以便它们的作用域仅对当前线程可见。
  8.  
  9. 在finally块中完成后,始终关闭语句
  10. public Data getMyData() {
        Connection conn = null;
        Statement statement = null;
        try {
            conn = ConnectionPool.getConnection();
            statement conn.prepareStatement("select mydata from mytable");
            //execute statement, get results
            //return Data
        }finally{
            if (statement != null) statement.close();        
            if (conn != null) conn.close(); //release the connection back to the pool
        }
    }
    

    只要您的连接池是线程安全的,此代码也应该是线程安全的,因为您永远不会在线程之间共享连接或语句。

答案 1 :(得分:0)

如果我真的很绝望,我会尝试以下方法来调试问题:

首先,我将为JDBC连接对象创建一个包装类。每个包装器方法将当前线程指针与最后一个操作的线程指针进行比较。如果它们相同,则调用包装的连接。否则它会记录一个错误,并使用堆栈跟踪来准确显示调用的位置。

接下来,我将找到创建JDBC连接的所有位置,并更改它们以使用我的包装类的实例包装连接。

最后,我运行应用程序,并设置一些内容来查看日志。