【问题标题】:JDBC and ThreadingJDBC 和线程
【发布时间】:2009-08-01 06:34:22
【问题描述】:

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

我正在使用 ExecutorService 来运行线程,但我想知道,每个线程应该获得自己的连接(因为它需要更新数据库)还是可以使用与查询初始结果相同的连接?

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

【问题讨论】:

    标签: java oracle jdbc


    【解决方案1】:

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

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

    您还可以考虑通过 PreparedStatement 进行批量更新,这样线程就不会在行锁和表锁方面相互绊倒,使用以下结构:

    • 1 个查询线程
    • NCPU 处理线程
    • 1 个批量更新线程

    就像一个迷你 db 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();
    

    【讨论】:

    • 谢谢!!!我有一个查询线程和 N 个线程用于处理。如何使用准备好的语句进行批量更新?
    • @Ngetha:如果这回答了您的问题,接受答案:meta.stackexchange.com/questions/5234/…(您的其他问题也是如此。)
    • @ kd304: “您应该始终为单独的线程使用单独的连接,因为驱动程序以这种方式不是线程安全的”那些将是不兼容的驱动程序,那么,不是吗? docs.oracle.com/javase/1.3/docs/guide/jdbc/spec/…
    • 你不能让 JDBC 拒绝 PreparedStatement API 线程安全——在多个线程访问同一个 PreparedStatement 实例的意义上。如果不同的线程使用不同的实例,那么它们是否是线程安全的就是一个合法的驱动程序一致性问题。
    【解决方案2】:

    如果您查看 Oracle jdbc OracleConnectionOraclePreparedStatement 的代码,大多数重要方法都是同步的,因此它们是“线程安全的”。在多个线程中使用单个Connection 不会给您带来最大的效率,因为每个线程都需要等待ConnectionPreparedStatement(尤其是execute)的操作完成,然后再执行它们自己的操作。

    【讨论】:

    • @akf:虽然问题特别提到了 Oracle 9i,但依赖于实现特定的行为并不是一个好主意。当然,不能保证其他供应商的 JDBC 堆栈是线程安全的。 AFAIK,JDBC 规范不需要它。
    • 您不能使 PreparedStatement API 线程安全。您不能通过同步其所有方法来使其成为线程安全的。这是一个有状态的 API。必须重新设计 API,以使通常可以跨线程安全地访问 PreparedStatement 实例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2014-10-09
    • 2014-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多