即使在spring事务中使用了可序列化的隔离级别,我也遇到了并发问题。我的用例是,用户将以以下格式提供要在数据库中更新的配置。
{A1: [B1, B2, B3]}我必须将它保存在下面的实体中。
A {
@OneToMany
List<B> bList;
}
B {
@ManyToOne
A a;
Boolean isDeleted;
}当存在保存配置的并发请求时,会插入比预期更多的B。请参考下面的场景。
Initial enitites in database: A1 -> []
Transaction 1 - given config {A1: [B2]}
Reads A1 -> []
Insert B2
Transaction 2 - given config {A1: [B3]}
Reads A1 -> []
Insert B3
Final in database: A1 -> [B2, B3] when expected is either A1 -> [B2, B3-deleted] or A1 -> [B2-deleted, B3].即使经过大量的研究,我也找不到解决这个问题的适当方法。根据本文(https://sqlperformance.com/2014/04/t-sql-queries/the-serializable-isolation-level),当使用SQL Server作为操作顺序是有效的序列化之一时,这种情况总是可能发生的。
发布于 2021-09-13 07:33:19
这最好通过引入乐观锁定的版本列来处理。不需要使用SERIALIZABLE隔离级别。只需使用
A {
@Version
long version;
@OneToMany
List<B> bList;
}并确保在加载A时使用LockModeType.OPTIMISTIC_FORCE_INCREMENT。这样,“序列化”将基于所谓的“聚合根”的锁,即A。
通过这样做,一个事务将成功,另一个事务将失败,因为在每个事务结束时,只有在其间值不变的情况下,version列才会递增。如果在此期间发生更改,它将回滚两个事务中的一个,您将看到一个OptimisticLockException。
https://stackoverflow.com/questions/69014760
复制相似问题