问题描述
我在我的项目中使用 Spring Boot、Spring Data、JPA(Hibernate) 和 MysqL。这是来自我的存储库接口的方法签名:
@Lock(LockModeType.pessimistic_READ)
@QueryHints({ @QueryHint(name = "javax.persistence.lock.timeout",value = "5000") })
@Query("select b from book b where b.id = :bookId")
Optional<Book> findBookCustom(Long bookId);
当我检查 sql 日志时,我可以看到“for shared”子句附加到了 select 语句中。
这是 MysqL documentation 关于共享锁的引用:
如果这些行中的任何一行被另一个尚未提交的事务更改,您的查询将等到该事务结束,然后使用最新值。
我实际上可以通过从另一个线程更新书来触发阻塞行为。当我暂停更新线程(书更新后)然后启动阅读线程时,我可以看到阅读线程被阻塞了。问题是读取线程等待大约 50 秒(我想这是默认的等待值),直到抛出超时异常。我在 QueryHint 中提供的值 5000 没有生效。我也尝试过直接使用EntityManager发出JPQL select语句,但结果是一样的。关于如何将超时设置为 5 秒的任何想法?
解决方法
我们可以通过工作台或 cmd-line 检查您的 MySQL 设置吗:
select @@innodb_lock_wait_timeout
然后尝试通过以下方式将其设置为新值:
set session innodb_lock_wait_timeout = 5
您现在可以通过 JPA 查询获取悲观锁,并且会将 LockTimeout 设置为 5 秒。有关详细信息,请查看 MySQL documentation。
根据使用的持久性提供程序和数据库,提示可能会也可能不会被观察到。
希望这会有所帮助。干杯!
更新
如果不想在他们的 MySQL 环境中修改会话。可以将以下设置放入应用程序属性文件:
spring.jpa.properties.javax.persistence.query.timeout=5000
,
MySQL 不支持查询锁超时,因此 @QueryHints({ @QueryHint(name = "javax.persistence.lock.timeout",value = "5000") })
被忽略
欲知更多详情:https://blog.mimacom.com/handling-pessimistic-locking-jpa-oracle-mysql-postgresql-derbi-h2/