我想要一个 getOrCreateFoobar(id)
通过 id
获取已经存在的 Foobar 的方法或者用 id
创建/插入一个新的 Foobar .
此方法将以高度并发的方式调用,因此我必须序列化/同步对此原子获取或创建的访问,以便不会有两个并发请求两次创建具有相同 ID 的 Foobar。
由于该实体可能还不存在,所以还没有我可以锁定以同步的行。此外,全表锁似乎也不是一个好主意——死锁灾难的潜在秘诀(?)
有这种模式可以创建类似 LockEntity
的人造实体它可能具有类似 Name
的属性.对于每个用例,我提供了一个行/实例,如 Name=GET_OR_CREATE_FOOBAR
.然后在带有 PESSIMISTIC_WRITE
的存储库中使用锁:
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT e FROM LockEntity e WHERE name = :name")
LockEntity obtainLock(@Param("name") String name);
然后可以像这样使用:
obtainLock("GET_OR_CREATE_FOOBAR")
// now we hold the lock and are synchronized
get()
if (doesNotExistYet) create()
commit / release-lock
有没有更好/更轻量级的方式?
最佳答案
由于参数是 id
,并且您只期望返回一个值,因此可以安全地假设 id
是唯一的,因此创建一个 UNIQUE列上的 INDEX
(如果它还不是主键),不可能两个并发请求创建具有相同 ID 的 Foobar 两次。 p>
其中一个会失败,然后它必须等待足够长的时间让第一个提交新创建的记录,然后从数据库中读取它。
loop:
get()
if found:
return it
insert()
if ok:
return it
if failure is not duplicate value error:
fail
short wait
end loop
关于java - 在哪里锁定以进行实体行的原子获取或创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54355908/