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

如何通过单元测试验证OptimisticLockException的触发行为?

解决乐观锁测试不触发OptimisticLockException的问题

核心问题分析

你当前的测试用例里,entity_1和entity_2的ID分别是789和987,这是两个完全独立的数据库记录。乐观锁冲突只会发生在同一个ID的实体实例、版本号不一致的场景下,所以第二次更新自然不会抛出异常。

具体修正步骤

1. 调整测试用例,使用同一ID的两个实体实例

创建两个ID相同、初始版本号一致的EntityA实例,模拟两个线程/事务同时加载同一条记录的场景:

// 创建两个ID相同、版本号都是2的实体实例
EntityA entity_1 = createEntity("789", 2);
EntityA entity_2 = createEntity("789", 2);

// 先更新第一个实例,此时数据库中该记录的版本号会被更新(比如变成3)
service.update(entity_1, "attr1");
// 再更新第二个实例,它的版本号还是旧的2,此时触发乐观锁冲突
assertThrows(OptimisticLockException.class, () -> service.update(entity_2, "attr2"));

verify(jpaRepository, times(2)).save(any(EntityA.class));

2. 修改update方法,确保异常被抛出

你的update方法里捕获了OptimisticLockException但只打日志没重新抛出,导致测试代码无法捕获到异常。需要调整方法逻辑:

public void update(EntityA entityA, String attribute) {
    try {
        entityA.setSomeAttribute(attribute);
        jpaRepository.save(entityA);
    } catch (OptimisticLockException e) {
        log.debug(e.getMessage());
        // 重新抛出异常,让上层(测试代码)能捕获到
        throw e;
    }
}

3. 单元测试中模拟JPA的版本检查逻辑(如果使用Mock)

如果你的测试是用Mock框架(比如Mockito)模拟JpaRepository,需要手动模拟版本冲突时抛出异常的场景:

// 第一次save正常执行,模拟版本号更新
when(jpaRepository.save(argThat(entity -> entity.getId().equals("789") && entity.getLastChange().equals(new Timestamp(2)))))
    .thenAnswer(invocation -> {
        EntityA entity = invocation.getArgument(0);
        entity.setLastChange(new Timestamp(3));
        return entity;
    });

// 第二次save时,因为版本号不匹配,抛出OptimisticLockException
when(jpaRepository.save(argThat(entity -> entity.getId().equals("789") && entity.getLastChange().equals(new Timestamp(2)))))
    .thenThrow(new OptimisticLockException("版本冲突"));

4. 注意版本字段Timestamp的使用细节

使用Timestamp作为版本字段时,要确保JPA能正确识别版本变更:

  • 避免手动设置lastChange字段,让JPA自动维护(如果需要手动更新,确保每次更新时版本字段的值严格递增)
  • 也可以考虑改用Long类型的版本号,更直观且不易出现时间精度问题:
@Version
private Long version;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 09:15:30