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

Spring Data @Lock(LockModeType.PESSIMISTIC_WRITE) 不生效问题求助

问题原因与解决方案

为什么当前代码达不到预期

  • PESSIMISTIC_WRITE悲观写锁的核心作用是阻止其他事务对锁定的记录执行修改、删除或添加写锁操作,但默认不会阻止其他事务读取这些记录。
  • Oracle数据库默认的事务隔离级别是READ COMMITTED,在该级别下,其他事务可以读取到已提交的数据版本,即使当前事务持有写锁,未提交的修改不会被其他事务读取,但原有已提交的记录依然可见。

解决方案

根据业务需求,提供两种可行方案:

方案1:调整事务隔离级别到SERIALIZABLE

该级别会强制所有事务串行执行,其他事务在当前事务提交前,无法读取到被锁定的记录(即使是原有已提交的数据)。但会显著降低系统并发性能,仅适合并发量极低的场景。

  • 全局配置(以HikariCP连接池为例):
    在application.properties中添加:
    spring.datasource.hikari.transaction-isolation=TRANSACTION_SERIALIZABLE
    
  • 局部配置(仅对特定事务生效):
    在调用该查询方法的服务层方法上添加:
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public List<Customer> getCustomersByOrgId(Long orgId) {
        return customerRepository.fetchCustomersByOrgId(orgId);
    }
    

方案2:使用Oracle原生SELECT ... FOR UPDATE增强锁控制

如果只需要阻止其他事务修改/删除这些记录,同时允许读取原有数据(只是不想让其他事务也获取写锁),可以修改查询为原生SQL并显式使用FOR UPDATE:

@Query(value = "SELECT * FROM CUSTOMER c WHERE c.org_id = ?1 FOR UPDATE", nativeQuery = true)
public List<Customer> fetchCustomersByOrgId(Long orgId);

这种方式下,其他事务如果尝试对这些记录加写锁(比如执行修改操作或同样的加锁查询)会被阻塞,但普通的SELECT查询依然可以读取到记录。

注意事项

  • 不要滥用高隔离级别或悲观锁,避免不必要的性能损耗。
  • 如果业务需求是“避免其他事务看到未提交的修改”,Oracle的READ COMMITTED已经满足,因为其他事务只会读取已提交的数据,当前事务未提交的修改不会被看到。如果需求是“完全看不到这些记录直到当前事务提交”,只能选择SERIALIZABLE隔离级别。

内容的提问来源于stack exchange,提问作者yaghob abbasi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 08:01:22