【问题标题】:Concurrency - DB access并发 - 数据库访问
【发布时间】:2011-05-07 00:18:42
【问题描述】:

我需要处理检索待处理记录并将它们更新为“处理中”状态作为工作单元。我想确保下面的代码支持并发和其他线程等到我当前的线程被处理。实现这一目标的最佳方法是什么?

public Collection<Object> processPendingMessages() {
    Collection<Object> messages = null;
    //Retrieve pending messages
    messages = messageDAO.getPendingMessages(Direction.INBOUND);
    //Update pending messages to Inprocess
    if (messages!=null && messages.size()>0) {
        messageDAO.updateMessagesToInprocess(messages); 
    } 
    return messages;
}

我们非常感谢您的意见。 谢谢。

【问题讨论】:

    标签: java concurrency thread-safety java.util.concurrent


    【解决方案1】:

    您不想通过使用(同步)单独处理 jvm 级别的 DBAccess 并发。在您的情况下,访问数据库是不可能的,仅在 jvm 级别进行同步是不可能的。您还需要在数据库连接级别处理并发,如下所示。就 DBaccess 而言,您还没有提到 DAO 层中的实现类型,但无论它可能是什么,以下 JDBC 隔离级别都应该对您的实现有意义,无论它是什么(JDBC,JPA 与休眠或 EJB 等)。通读下面的隔离级别,并确定哪一个适合您的应用程序。一切顺利。

    事务隔离级别指定事务中的语句可以看到哪些数据作为一个事务单元。这些级别通过定义针对同一目标数据源的事务之间可能发生的交互,直接影响并发访问的级别。

    数据库异常

    数据库异常是生成的结果,从单个事务的范围来看似乎不正确,但从所有事务的范围来看是正确的。不同类型的数据库异常描述如下:

    在以下情况下会发生脏读: 事务 A 在表中插入一行。 事务 B 读取新行。 事务 A 回滚。 事务 B 可能已根据事务 A 插入的行对系统进行了工作,但该行从未成为数据库的永久部分。

    在以下情况下发生不可重复读取: 事务 A 读取一行。 事务 B 更改行。 事务 A 再次读取同一行并获得新结果。

    幻读发生在以下情况: 事务 A 读取 SQL 查询中满足 WHERE 子句的所有行。 事务 B 插入满足 WHERE 子句的附加行。 事务 A 重新评估 WHERE 条件并选择额外的行。

    处理上述每个异常的隔离级别

    JDBC_TRANSACTION_NONE 这是一个特殊常量,表示 JDBC 驱动程序不支持事务。

    JDBC_TRANSACTION_READ_UNCOMMITTED 此级别允许事务查看对数据的未提交更改。在这个级别上,所有数据库异常都是可能的。

    JDBC_TRANSACTION_READ_COMMITTED 在事务内部进行的任何更改在事务提交之前在其外部是不可见的。这可以防止脏读。

    JDBC_TRANSACTION_REPEATABLE_READ 读取的行保留锁,以便在事务未完成时另一个事务无法更改它们。这不允许脏读和不可重复读。仍然可以进行幻读。

    JDBC_TRANSACTION_SERIALIZABLE 表为事务锁定,因此 WHERE 条件不能被其他向表添加值或从表中删除值的事务更改。这可以防止所有类型的数据库异常。

    setTransactionIsolation 方法可用于更改连接的事务隔离级别。

    【讨论】:

    • 谢谢!这就是一切都引导我去的地方。感谢您的澄清。
    【解决方案2】:

    你应该让数据库处理并发。

    在您的 DAO 中,您可以发出 sql 查询:

    // works on oracle.
    // query may differ depending on vendor
    select * from test where id=? for update 
    

    第一个线程将能够获取锁,但后续线程如果执行查询将阻塞。一旦第一个线程提交/回滚,等待线程中的一个将解除阻塞。这样,您就可以让读者一次阅读一篇。

    【讨论】:

    • 谢谢,我也是这么想的。对并发阅读过多,我不太确定是将其留给 JVM 还是实现事务管理器。感谢您的 cmets。
    【解决方案3】:

    为了防止代码中出现竞争条件,请使用synchronized关键字来阻止线程访问代码块,直到前一个线程完成它。

    【讨论】:

    • 抱歉,代码一部署到集群就不能工作了(而且总是这样)。
    • 不,这不起作用(没有)。如果您查看代码,所有使用的变量都被限制在每个单独的线程中。没有其他线程的干预;其中多个线程并行运行。那是我的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-19
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多