SpringBoot从CSV导入JPA记录报错:行被其他事务修改/删除
解决SpringBoot CSV导入News数据时的ObjectOptimisticLockingFailureException问题
核心原因分析
这个异常本质是乐观锁冲突:你的News实体类大概率带有@Version注解的乐观锁字段,导入过程中要么是同一行数据被重复操作,要么是字段值(比如version)与数据库预期不符,触发了乐观锁校验失败。
具体排查与解决步骤
1. 检查News实体类的乐观锁配置
- 如果实体类中有
@Version注解的字段(比如private Integer version;):- 若为初始化数据场景,可临时给每条导入的News对象设置初始version值(如
news.setVersion(0);),确保和数据库的初始校验逻辑匹配。 - 若不需要在导入阶段启用乐观锁,可临时移除
@Version注解(导入完成后再恢复),或者在导入代码中通过实体管理器禁用乐观锁校验。
- 若为初始化数据场景,可临时给每条导入的News对象设置初始version值(如
2. 校验CSV文件内容
- 检查CSV的id列是否存在重复值:重复的id会导致多次尝试插入/更新同一行数据,引发乐观锁冲突。
- 若CSV包含version列,确保值符合数据库规则(新记录设为0,更新已有记录则要与数据库当前version一致);若没有version列,在代码中统一给导入对象设置初始version。
3. 修正数据初始化代码
- 避免复用实体对象:确保每处理一行CSV数据都创建新的News实例,不要循环复用同一个对象,否则多次保存时version字段无法自动更新,触发校验失败。
- 控制事务与数据操作逻辑:
- 若为初始化数据,建议先清空News表(
newsRepository.deleteAll();),再批量导入(newsRepository.saveAll(newsList);),避免与已有数据冲突。 - 检查是否存在多事务并发操作News表的情况(比如其他初始化任务、定时任务),暂停这些操作后再执行导入。
- 若为初始化数据,建议先清空News表(
示例修正代码
假设你的导入逻辑如下,可调整为:
// 读取CSV数据 List<News> newsList = csvReader.parseCsvFile("news_data.csv"); // 初始化乐观锁字段(如果实体类有@Version) newsList.forEach(news -> news.setVersion(0)); // 清空已有数据(仅初始化场景使用) newsRepository.deleteAllInBatch(); // 批量保存 newsRepository.saveAllAndFlush(newsList);
内容的提问来源于stack exchange,提问作者Gwendal
相关产品推荐
相关产品推荐

