Hibernate技术问询:能否获取已被悲观写锁锁定的实体并加锁?
Hibernate 悲观锁与Session.lock()的使用疑问解答
核心问题拆解与解答
1. 能否先获取被其他会话以LockMode.PESSIMISTIC_WRITE锁定的实体,再通过Session.lock()显式加锁?
可以,但行为取决于数据库锁机制和Hibernate配置:
- 若通过普通查询(如
get()/load()不带锁模式)获取实体后,调用Session.lock(entity, LockMode.PESSIMISTIC_WRITE),Hibernate会向数据库发送对应锁语句(如MySQL的SELECT ... FOR UPDATE)。 - 若该实体已被其他会话持有
PESSIMISTIC_WRITE锁,当前会话会阻塞等待直到锁释放;若数据库配置了锁超时,则会抛出LockTimeoutException。
2. 是否必须在检索实体时就指定锁模式?
不是必须的。检索时指定锁模式(如session.get(Entity.class, id, LockMode.PESSIMISTIC_WRITE))是一次性加锁的便捷方式,但Session.lock()提供了事后加锁的能力,二者互补而非互斥。
3. 若检索时不指定锁模式,Session.lock()的存在意义是什么?仅用于锁升级吗?
Session.lock()的用途不止于锁升级,常见场景包括:
- 事后加锁:先加载实体做只读校验,确认需要修改后再显式加写锁,避免不必要的锁竞争。
- 锁升级:先以
LockMode.PESSIMISTIC_READ加载实体(共享锁),后续需要修改时,通过lock()升级为LockMode.PESSIMISTIC_WRITE(排他锁)。 - 重新获取锁:当实体锁因会话缓存状态过期等原因失效时,可通过
lock()重新向数据库申请锁,保障后续操作一致性。
额外注意:
Session.lock()仅针对持久化状态的实体(当前会话已管理的实体),若为游离状态实体,调用lock()会先将其关联到会话,再执行锁操作。- 不同数据库对锁的支持存在差异,部分数据库不支持锁升级,此时调用
lock()升级锁会直接抛出异常,需结合数据库特性使用。
内容的提问来源于stack exchange,提问作者elsamuray7
相关产品推荐
相关产品推荐

