在 Spring-Boot 中处理并发事务
Handling concurrent transaction in Spring-Boot
所以,这似乎是一个非常菜鸟的问题,但经过一番谷歌搜索后,我找不到最佳方法。
问题:有一个 Spring- 启动应用程序,与数据库交互 (MySQL)。
考虑一个 table T1,我不想让每个用户只有一个有效条目。
因此,如果出现下一个条目,它会软删除(通过设置 deleted-at 列)该用户的现有行并创建一个新条目。
现在当有多个请求时,问题就来了,几乎同时。
我的事务块看起来像这样:
@Transactional
someMethod() {
CheckIfAnyValidEntryForUser(U1);
SoftDeleteExistingEntries(U1);
DoComputation(); // Takes around a second.
InsertNewRow();
}
现在如果在短时间内有多个请求,那么我的代码最终会为单个用户插入多个有效条目。
由于我要编辑的行之前可能不存在,所以我无法通过版本号进行乐观锁定。
正在考虑在此 someMethod 上获取全局锁,但这会大大增加我的延迟。
另一种方法可能是在数据库中为列(包括 deleted-at 列)使用复合唯一键。然后在代码中处理提交失败。
这好像是一个很常见的问题,那么一般是怎么处理的呢?
什么是最好的方法?
你可以使用@Transactional
注解的isolation
属性并将这个属性设置为Isolation.SERIALIZABLE
:
@Transactional(isolation= Isolation.SERIALIZABLE)
注意:
Spring by default use DEFAULT isolation strategy which uses the default isolation level of underlying datastore. Using
SERIALIZABLE isolation makes your transactions executed with locking at read, write, range; so they appear as if they were executed
in a serialized way, preventing dirty reads, non-repeatable reads and
phantom reads.
还有
Exclusively designed for use with Propagation.REQUIRED or Propagation.REQUIRES_NEW since it only applies to newly started transactions. Consider switching the "validateExistingTransactions" flag to "true" on your transaction manager if you'd like isolation level declarations to get rejected when participating in an existing transaction with a different isolation level.
所以,这似乎是一个非常菜鸟的问题,但经过一番谷歌搜索后,我找不到最佳方法。
问题:有一个 Spring- 启动应用程序,与数据库交互 (MySQL)。 考虑一个 table T1,我不想让每个用户只有一个有效条目。 因此,如果出现下一个条目,它会软删除(通过设置 deleted-at 列)该用户的现有行并创建一个新条目。 现在当有多个请求时,问题就来了,几乎同时。
我的事务块看起来像这样:
@Transactional
someMethod() {
CheckIfAnyValidEntryForUser(U1);
SoftDeleteExistingEntries(U1);
DoComputation(); // Takes around a second.
InsertNewRow();
}
现在如果在短时间内有多个请求,那么我的代码最终会为单个用户插入多个有效条目。
由于我要编辑的行之前可能不存在,所以我无法通过版本号进行乐观锁定。
正在考虑在此 someMethod 上获取全局锁,但这会大大增加我的延迟。
另一种方法可能是在数据库中为列(包括 deleted-at 列)使用复合唯一键。然后在代码中处理提交失败。
这好像是一个很常见的问题,那么一般是怎么处理的呢? 什么是最好的方法?
你可以使用@Transactional
注解的isolation
属性并将这个属性设置为Isolation.SERIALIZABLE
:
@Transactional(isolation= Isolation.SERIALIZABLE)
注意:
Spring by default use DEFAULT isolation strategy which uses the default isolation level of underlying datastore. Using SERIALIZABLE isolation makes your transactions executed with locking at read, write, range; so they appear as if they were executed in a serialized way, preventing dirty reads, non-repeatable reads and phantom reads.
还有
Exclusively designed for use with Propagation.REQUIRED or Propagation.REQUIRES_NEW since it only applies to newly started transactions. Consider switching the "validateExistingTransactions" flag to "true" on your transaction manager if you'd like isolation level declarations to get rejected when participating in an existing transaction with a different isolation level.