java - 在哪里锁定以进行实体行的原子获取或创建

标签 java postgresql hibernate jpa

我想要一个 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/

相关文章:

java - 缺少 tomcat 资源,servlet 未运行

java - Spring 启动: Consider defining a bean named 'entityManagerFactory' in your configuration

java - 如何用 HashMap 替换 SQL 查询字符串

jquery - Heroku PostgreSQL 更改 sortable_list POST?

java - 在 Maven 中配置 hibernate-jpamodelgen

java - Spring JPA 存储库删除方法不起作用

java - 为什么 Jenkins 的启动脚本在 Java 11 (Ubuntu) 下失败?

Python、Postgresql 从 csv 复制时遇到问题

java - 在 spring-mvc 中使用抽象工厂模式时出现空指针异常

database - Heroku POSTGRESQL - "Too many connections for role"错误