并发 - 数据库访问

时间:2011-05-07 00:18:42

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

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

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;
}

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

3 个答案:

答案 0 :(得分:5)

您不希望单独使用(synchronized)来处理jvm级别的DBAccess并发。在您的情况下,访问是数据库,仅在jvm级别的同步是不可能的。您还需要在数据库连接级别处理并发,如下所示。关于DBaccess,你还没有提到你的DAO层有什么样的实现,但是无论它是什么,JDBC的以下隔离级别对你的实现都是有意义的,无论它是什么(JDBC,JPA with Hibernate或EJB等)。仔细阅读下面的隔离级别,并确定哪一个适合您的应用。最好的实施。

事务隔离级别指定事务中作为事务单元的语句可见的数据。这些级别通过定义事务与同一目标数据源之间可能的交互来直接影响并发访问级别。

DATABASE ANOMOLIES

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

在以下情况下发生脏读: 事务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 方法可用于更改连接的事务隔离级别。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

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

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

第一个线程将能够获取锁,但后续线程将在执行查询时阻塞。一旦第一个线程有提交/回滚,其中一个等待线程将解除阻塞。通过这种方式,您可以让读者一次阅读一个。