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

@Transactional与@Lock问题排查:为何触发DataIntegrityViolationException?

问题分析与解决方案

异常原因分析

  • 悲观锁范围错误:findOneForUpdate方法虽加了@Lock(LockModeType.PESSIMISTIC_WRITE)悲观写锁,但查询仅按clientId过滤,未匹配完整的ComplexKey(包含clientId、documentType、resetDate)。多线程场景下,同一clientId下不同ComplexKey的请求会干扰彼此,甚至同一ComplexKey的请求也因锁范围不精准,无法阻止并发插入操作。
  • 无锁查询引发并发冲突:当updateInCache=false时,get方法直接调用无锁的findById,多个线程同时查询同一ComplexKey会同时得到空结果,随后都执行put里的save操作,尝试插入同主键的实体,触发数据库唯一约束,抛出DataIntegrityViolationException。
  • 事务与锁协同失效:尽管@Transactional(REQUIRES_NEW)保证每个调用开启独立事务,但锁的作用范围错误导致锁无法覆盖目标实体,事务的隔离性未发挥应有的作用。

注解层面调整方案

1. 修正悲观锁的查询范围

调整findOneForUpdate的查询条件,匹配完整ComplexKey,确保锁精准锁住目标实体:

@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select e from ENumber e where e.clientId = :clientId and e.documentType = :documentType and e.resetDate = :resetDate")
Optional<ENumber> findOneForUpdate(
    @Param("clientId") Long clientId,
    @Param("documentType") String documentType, // 类型根据实际业务调整
    @Param("resetDate") LocalDate resetDate // 类型根据实际业务调整
);

2. 给get方法添加悲观锁

让get方法复用加锁的查询逻辑,避免无锁场景下的并发插入:

default Optional<ENumber> get(ComplexKey key) {
    return findOneForUpdate(key.getClientId(), key.getDocumentType(), key.getResetDate());
}

或者直接给findById添加锁注解(基于Spring Data JPA派生查询):

@Lock(LockModeType.PESSIMISTIC_WRITE)
Optional<ENumber> findById(ComplexKey key);

3. 优化事务与锁的配合

@Transactional(REQUIRES_NEW)的配置无需改动,确保每个getNumber调用都在独立事务中执行,配合精准的悲观锁,就能让同一ComplexKey的并发请求串行化处理,从根源避免重复插入。

可选:强化插入/更新的原子性

作为补充优化,调整put方法的逻辑,确保在锁保护下完成实体的查询-更新/插入操作:

default void put(ComplexKey key, ComplexNumber complexNumber) {
    ENumber number = numberRepository.findById(key)
        .map(existing -> {
            existing.setPrefix(complexNumber.getPrefix());
            existing.setNumber(complexNumber.getNumber());
            return existing;
        })
        .orElseGet(() -> new ENumber()
            .setKey(key)
            .setPrefix(complexNumber.getPrefix())
            .setNumber(complexNumber.getNumber())
        );
    numberRepository.save(number);
}

内容的提问来源于stack exchange,提问作者Evgenia Rubanova

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 21:50:51