JDBC和线程

时间:2009-08-01 06:34:22

标签: java oracle jdbc

我有一个程序需要在给定的时间间隔内查询数据库,并且它调用的记录执行一些操作,然后再次更新表。

我正在使用ExecutorService来运行线程,但是我想知道,如果每个线程都有自己的连接(因为它需要更新数据库),或者我可以使用我用来查询初始结果的相同连接吗?

可以连接池工作,我在Oracle 9i上。

2 个答案:

答案 0 :(得分:10)

您应该始终对单独的线程使用单独的连接,因为驱动程序不是以这种方式的线程安全。连接池可以帮助您,因为它允许以安全的方式重用连接。

您还可以执行查询调度模式 - 如果我正确理解您的问题 - 其中一个线程负责查询和启动可能更新数据库的N个线程 - 所有这些线程都有单独的连接对象。

您可能还考虑通过PreparedStatement进行批量更新,因此线程不会在行和表锁中相互偶然发生,使用以下结构:

  • 1个查询主题
  • NCPU处理线程
  • 1批量更新帖子

像迷你数据库fork-join。

修改

如何使用Pstmt进行批量更新的示例:

PreparedStatement pstmt = connection.prepareStatement(
    "UPDATE table SET field=? WHERE id=?");
for (int i = 0; i < 100; i++) {
    pstmt.setInt(1, i * i);
    pstmt.setInt(2, i);
    pstmt.addBatch();
}
pstmt.executeBatch();
pstmt.close();

或者您可以在循环中查询更新请求从处理线程到达的队列:

class WhatToUpdate {
    public int id;
    public int value;
}
Queue<WhatToUpdate> queue = new LinkedBlockingQueue<WhatToUpdate>();

PreparedStatement pstmt = connection.prepareStatement(
    "UPDATE table SET field=? WHERE id=?");

int poisons = THE_NUMBER_OF_PROCESSING_THREADS;
while (true) {
    WhatToUpdate record == queue.take();
    if (record == null) { // poison pill
        if (--poisons <= 0) {
            break;
        }
    }
    pstmt.setInt(1, record.value);
    pstmt.setInt(2, record.id);
    pstmt.addBatch();
}
pstmt.executeBatch();
pstmt.close();

答案 1 :(得分:2)

如果查看Oracle jdbc OracleConnectionOraclePreparedStatement的代码,大多数重要方法都是同步的,因此它们是“线程安全的”。跨多个线程使用单个Connection将无法提供最高效率,因为每个线程都需要等待ConnectionPreparedStatement(尤其是execute)的操作在完成自己的行动之前完成。