You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL集群环境下PESSIMISTIC_WRITE行锁不生效怎么解决?

悲观写锁未生效常见原因及解决方案

首先要先确认底层执行的查询语句是否携带FOR UPDATE后缀(PostgreSQL中PESSIMISTIC_WRITE锁对应的实现就是行级写锁语句SELECT ... FOR UPDATE),可以通过在配置中开启SQL打印验证:

# application.properties 新增配置
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

如果打印的查询语句没有FOR UPDATE,说明锁注解根本没有生效,可按以下顺序排查:

1. 事务未生效

Spring的@Transactional注解存在多个不生效的场景,这是锁失效最常见的原因:

  • 标注@Transactional的方法不是public修饰
  • 方法被同一个类内部的非事务方法直接调用(没有经过Spring代理类)
  • 没有指定回滚异常范围,默认只对RuntimeException和Error回滚,建议显式配置@Transactional(rollbackFor = Exception.class)
  • 项目存在多数据源时没有指定对应的事务管理器

2. JPA缓存跳过了数据库查询

如果持久化上下文的一级缓存、或者二级缓存中已经存在目标实体,JPA会直接返回缓存中的对象,不会发起数据库查询,自然不会触发数据库层面的行锁。
可以在Repository查询方法上添加缓存跳过配置,强制走数据库查询加锁:

import javax.persistence.QueryHint;
import org.springframework.data.jpa.repository.QueryHints;

@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints(value = {
    // 跳过缓存查询数据库
    @QueryHint(name = "javax.persistence.cache.retrieveMode", value = "BYPASS"),
    // 查询后刷新缓存
    @QueryHint(name = "javax.persistence.cache.storeMode", value = "REFRESH"),
    // 可选:配置锁超时时间3000ms,避免长时间阻塞
    @QueryHint(name = "javax.persistence.lock.timeout", value = "3000")
})
public Optional<LicenseCountEntity> findById(LicenseCountId licenseCountId);

3. 复合主键映射异常

你使用了复合主键LicenseCountId,需要确认两点:

  • 复合主键类实现了Serializable接口
  • 正确重写了equals()和hashCode()方法,保证主键匹配逻辑正确

4. 低版本Spring Data JPA兼容性问题

部分老旧版本的Spring Data JPA对默认findById方法的@Lock注解支持有缺陷,可以自定义显式查询语句绕过该问题:

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select l from LicenseCountEntity l where l.id.tenantId = :tenantId and l.id.serviceId = :serviceId")
Optional<LicenseCountEntity> findLockById(String tenantId, String serviceId);

注意事项

  • 锁持有的时间越短越好,避免大事务导致其他请求长时间阻塞甚至死锁
  • 加锁成功后,事务提交或回滚前,其他Pod的查询请求都会被阻塞,不会读到未提交的脏数据,也无法修改该行数据

内容的提问来源于stack exchange,提问作者Anant Bhatnagar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 10:54:04