【问题标题】:Locking mutual transactions execution锁定相互交易执行
【发布时间】:2012-01-03 22:42:08
【问题描述】:

我想用下面的例子来描述这个问题:

假设我们正在开发应用程序(基于 Hibernate JPA 和 Spring),该应用程序允许其用户执行两种必须以可序列化模式为每个用户执行的事务操作。只要应用程序必须同时健壮且性能良好,我们可以使用 ReentrantLock 周围的某种包装器进行同步:

void operation1(user) {
    userLockWrapper.lock(user.id); //gets ReentrantLock for specified id from internal map and locks it
    try {   
        //start transaction 
        //perform operation
        //commit transaction    
    } finally {
        userLockWrapper.unlock(user.id).
    }   
}
void operation2(user) {
    userLockWrapper.lock(user.id); //same wrapper instance as in operation1
    //same logic as in operation1   
}

现在假设为了提高可扩展性,我们将系统划分为两个独立模块,这些模块在不同的虚拟机中运行并使用相同的数据库,其中第一个模块负责操作 1,第二个模块负责操作 2。想到的第一个决定是使用悲观锁,例如:

@Transactional
void operation1(user) { //same goes for operation2
    //firing extra select for update sql statement here
    entityManager.find(User.class, user.id, LockModeType.PESSIMISTIC_WRITE) 
    //performing operation      
}

我想知道是否有更好的解决方案。希望得到社区的一些建议。

【问题讨论】:

    标签: java hibernate spring jpa transactions


    【解决方案1】:

    是的,有。使用乐观锁定。您只需向您的实体添加一个带有 @Version 注释的持久字段,并了解它是如何工作的。阅读http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#transactions-optimistic

    每次 Hibernate 将实体写入数据库时​​,它都会检查存储的版本是否与内存中的版本相同,并递增该版本。如果版本不匹配,它会抛出一个使事务回滚的问题。

    这将实现最佳吞吐量,也是唯一可以跨两个事务使用的系统:第一个事务加载对象,用户修改它(可能需要几分钟),第二个事务合并对象。

    【讨论】:

    • 其实我考虑过使用乐观锁,但是在这种情况下似乎不合适,因为应用程序不仅要对非陈旧数据进行操作,还要提供可以达到的最佳健壮性,因此回滚秒交易和取消操作不是一种选择。但是现在我认为这个问题可以通过锁定失败时的自动重试操作来解决。谢谢,我会深入研究的。
    猜你喜欢
    • 2010-09-14
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多