【问题标题】:Spring Data Pessimistic Lock timeout with Postgres使用 Postgres 的 Spring Data 悲观锁超时
【发布时间】:2015-09-29 20:01:45
【问题描述】:

我无法让 Spring Data 使用 NOWAIT 向 postgres 发送 FOR UPDATE。

我已经在存储库中尝试过:

@Lock(value = LockModeType.PESSIMISTIC_WRITE)
MyObject findByUuid(String uuid);

配置(sn-p)

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
    entityManagerFactoryRef = "docsEntityManagerFactory",
    transactionManagerRef = "docsTransactionManager",

@Bean(name = "docsEntityManagerFactory")
public EntityManagerFactory docsEntityManagerFactory(DataSource docsDataSource) {
props.setProperty("javax.persistence.lock.timeout", "0");
...

我什至在我的服务中注入了 EntityManager,这会返回 0:

logger.info(em.getProperties().get("javax.persistence.lock.timeout"));

但上面的内容只让我得到“更新”,NOWAIT 部分没有被设置。我是否设置了正确的东西(从另一篇文章看来这应该可行)。

这让我更接近,虽然我不想使用原始 sql

 @Lock(value = LockModeType.PESSIMISTIC_WRITE)
 @Query(value = "SELECT * FROM the_table WHERE uuid = :uuid FOR UPDATE NOWAIT", nativeQuery = true)
 MyObject findByUuid(@Param("uuid") String uuid);

这确实给了我一个 Lock 异常,但是 Spring 装饰的服务(代理)在返回时会抛出一个 Transaction/Rollback 异常,这意味着我不能给出我需要的方法的返回值。

问题: 1) 如何让 Spring Data 添加NOWAIT? 2)有没有办法返回值?我怀疑我需要自己处理事务,还是更改逻辑流程?不确定 Spring 是否会处理 NOWAIT,如果它的行为会有所不同。

我知道有类似的问题,但这略有不同。 我正在使用休眠 4.2.15、spring-data-jpa 1.7.1、postgres sql 9.3。

【问题讨论】:

  • Spring Data JPA 不会向 Postgresql 发送任何内容,而您的 JPA 提供程序会。 Hibernate(您可能正在使用的)是否支持添加 NOWAIT?
  • 好问题。查看我们使用的类(PostgresSQL82Dialect),它具有以下实现: getForUpdateNowaitString(...) { return this.getForUpdateString(...) + " nowait "; } 基于 HH-6452 应该这样做,这是唯一要检查的事情吗?
  • 但是,方言没有设置正确,所以它不起作用,现在它可以了。解决了,谢谢@NeilStockton

标签: hibernate postgresql jpa spring-data


【解决方案1】:

使用 PESSIMISTIC_FORCE_INCREMENT

【讨论】:

  • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性的 cmets 挤满你的代码,这会降低代码和解释的可读性!
  • 不知什么原因,这实际上有帮助
【解决方案2】:

javax.persistence.lock.timeout 在如下提供时也不适合我

@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout",value = "15000")})

但后来我尝试了其他有效的方法。现在我使用实体管理器配置我的休眠,而不是使用 @Repository 和 CrudRepository。使用 createQuery 以及锁定和设置锁定超时。并且此配置按预期工作。我有两个事务并行运行并试图锁定数据库中完全相同的行。第一个事务能够获得 WRITE 锁并在释放锁之前持有锁大约 10 秒。同时,第二个事务尝试在同一行获取锁,但由于 javax.persistence.lock.timeout 设置为 15 秒,它等待锁被释放,然后获取自己的锁。因此使流程序列化。

@Component
public class Repository {

    @PersistenceContext
    private EntityManager em;

    public Optional<Cache> getById(int id){
        List<Cache> list = em.createQuery("select c from Cache c where c.id = ?1")
                            .setParameter(1, id)
                            .setHint("javax.persistence.lock.timeout", 15000)
                            .setLockMode(LockModeType.PESSIMISTIC_WRITE)
                            .getResultList();


        return Optional.ofNullable(list.get(0));
    }

    public void save(Cache cache) {
        cache = em.find(Cache.class, cache.getId());
        em.merge(cache);
    }
}

确保此锁定机制位于事务内部,因为当事务提交或回滚时,锁定将被释放。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-30
    • 1970-01-01
    • 2018-10-22
    • 2015-11-28
    • 1970-01-01
    • 2017-03-25
    • 1970-01-01
    • 2018-01-10
    相关资源
    最近更新 更多