在Spring-Boot中处理并发事务

时间:2019-04-27 13:43:36

标签: java mysql spring spring-boot spring-transactions

因此,这似乎是一个非常菜鸟的问题,但经过一番谷歌搜索后,我找不到最佳方法。

问题:具有一个Spring-Boot应用程序,可与数据库(MySQL)交互。 考虑一个表T1,我不想为每个用户只有一个有效条目。 因此,如果出现下一个条目,它将软删除(通过设置Deleted-at列)该用户的现有行并创建一个新条目。 现在问题来了,几乎同时存在多个请求。

我的交易区块,看起来像这样:

@Transactional
someMethod() {
    CheckIfAnyValidEntryForUser(U1);    
    SoftDeleteExistingEntries(U1);
    DoComputation();   // Takes around a second.
    InsertNewRow();
}

现在,如果短时间内有多个请求,那么我的代码最终将为单个用户插入多个有效条目。

由于我要编辑的行可能以前不存在,因此无法按版本号进行乐观锁定。

本来想在此someMethod上获取Global-Lock,但这会使我的等待时间增加太多。

另一种方法可能是在数据库中为列(包括Deleted-at列)使用复合唯一键。然后处理代码中的提交失败。

这似乎是一个非常普遍的问题,那么通常如何处理? 最好的方法是什么?

1 个答案:

答案 0 :(得分:2)

您可以使用isolation批注的@Transactional属性,并将此属性设置为Isolation.SERIALIZABLE

@Transactional(isolation= Isolation.SERIALIZABLE)

请注意:

  

默认情况下,Spring使用 DEFAULT 隔离策略,该策略使用基础数据存储区的默认隔离级别。使用    SERIALIZABLE 隔离使您的事务在读取,写入和范围锁定时执行;所以它们看起来好像被执行了一样   以序列化的方式,防止脏读,不可重复读和   幻像读取。

  

专门设计用于Propagation.REQUIRED或Propagation.REQUIRES_NEW,因为它仅适用于新启动的交易。如果希望在参与具有不同隔离级别的现有事务时拒绝隔离级别声明,请考虑在事务管理器上将“ validateExistingTransactions”标志切换为“ true”。

相关问题