2009-07-29 46 views
2

我有一个Java JDBC应用程序,它使用多个线程从Oracle数据库检索信息。每个线程si应该定期执行一条语句,该语句在特定的表上执行一个选择(每个表的表不同)。关闭JDBC不需要的语句

线程是扩展Thread类的类的实例。该类有一个私有变量,用于存储与数据库的连接。该线程还有一个子线程,通过语句定期从表中删除一些信息。当我运行一个单线程(从单个表中获取数据)它完美的作品,但是当我运行多个线程(试图从多个表中获取数据)时,我得到一个错误,说我的语句在我之前关闭打印由该语句生成的整个结果集。

我的问题是:

为什么不同的线程结束我的发言? 为什么子线程不关闭父线程语句? 我能做些什么来防止这种情况发生?

我希望有人能帮忙。 Constantin

我不使用连接池,因为每个线程上的连接都会永久保持打开状态,因为我每20毫秒执行一次select语句,并且cild线程(拥有自己的连接)每隔10秒执行一次delete语句。

我不能将数据存储在数组中,因为就像我检索它时一样,我必须将它发送到一个用于处理的API。

我无法理解它。每个线程都是一个不同的实例(具有不同的参数,除用于连接aka用户,密码的那些参数外)(女巫没有任何静态内容)并关闭了其他语句。

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

下面是一个代码示例

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

的conn变量是一个连接,并在thrad的构造函数创建,可这是什么问题?

新的编辑

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

感谢您的帮助和抱歉,如果如果你确保你没有线程之间共享状态我听起来stubern和抱歉,没有从一开始就

+1

如果您每20毫秒运行一次查询,那么您应该明确地使用连接池。连接池的作用是保持连接打开。当你需要连接时调用getConnection()并且在你完成它时调用conn.close()。不要自己管理连接,因为当您看到现在连接时,您将不得不面对管理难题。 – 2009-07-29 12:27:18

+0

如果“每个线程都有它自己的连接对象,并且它有自己的语句和结果集对象”,那么也许你认为发生的并不是真正发生的事情。 – 2009-07-29 12:34:36

+0

连接对象是不是线程中的静态字段?如果其他线程无法看到它,则没有明显的理由关闭您的语句。 – akarnokd 2009-07-29 12:36:01

回答

3

表达我自己更清楚,你就不用再担心同步。

  1. 使用连接池。在执行每个数据库语句之前,从池中检索连接。即使您每秒获取并释放连接50次,连接到数据库的连接仍会保持池打开状态,并且只有当多个线程同时需要数据库连接时才需要新的连接。我建议你看看DBCP,它有一个强大的,线程安全和灵活的数据库连接池的良好实现。
  2. 使用局部变量来确保连接的范围意味着它只对当前线程可见。
  3. 当您完成数据库语句执行时,始终关闭连接(或将它们释放回池)。使用JDBC代码的finally块来完成此操作。
  4. 当再次创建语句时,请确保它们是本地的,以便它们的作用域仅对当前线程可见。
  5. 当你在finally块中完成它们时,总是关闭语句
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 
    } 
} 

只要你的连接池是线程安全的,这段代码也应该是线程安全的,你永远不会共享线程之间的连接或语句。

0

如果我真的绝望了,我想尝试以下调试问题:

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

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

最后,我会运行应用程序,并设置一些东西来观察日志。