使用JPA的.save()保存20条数据仅成功17条,求问题原因
这种情况我做项目时也碰到过,结合你的代码和场景,大概率是下面这几个原因,咱们一步步来排查:
一、先揪出代码里的明显笔误
你贴的代码里有个很容易忽略的错误:
List<MyBean> g=new ArrayList<>(); MyBean.add(mybean object); // 这里应该是g.add()吧?
如果实际代码里真的是用MyBean.add()而不是g.add(),那这些对象根本没被加入到要保存的List集合里!你可以在调用repository.save(g)之前加一行System.out.println(g.size());,看看集合里到底是不是真的有20个元素——这是最容易踩的低级坑。
二、数据库约束导致插入失败
如果集合元素数量没问题,那大概率是数据库的约束限制拦住了那3条数据:
- 主键/唯一键冲突:如果你的
MyBean实体主键不是自增策略,而是手动指定值,或者表中有其他唯一索引(比如某个字段加了UNIQUE约束),那当有重复值时,数据库会直接拒绝插入这几条数据。 - 非空/字段长度约束:比如某个字段在数据库中是
NOT NULL,但你那3条对象的这个字段是null;或者字符串字段长度超过了数据库定义的上限,都会导致插入失败。
排查方法:
- 把那3条没保存的对象拿出来,手动写SQL插入到数据库,看是否会报错;
- 开启JPA的SQL日志(比如Hibernate设置
spring.jpa.show-sql=true),看实际执行的INSERT语句,有没有哪几条抛出了约束异常。
三、事务或异常未被捕获
Spring Data JPA的save(Iterable<T>)本质是循环调用单条save,默认情况下如果某一条插入抛出异常,后面的都不会执行,但如果你的代码没有捕获异常,又不在事务环境下执行,就会出现前面17条成功插入、后面3条失败的情况——因为没有事务回滚,前面的已经提交到数据库了。
排查方法:
- 检查保存方法上是否加了
@Transactional注解; - 在save代码周围加try-catch块,捕获所有Exception,打印异常信息:
try { repository.save(g); } catch (Exception e) { e.printStackTrace(); // 可以打印具体的异常详情,比如约束冲突的字段 }
如果捕获到DataIntegrityViolationException,那基本就是数据库约束的问题了。
四、JPA批量配置缺失
如果你的JPA实现是Hibernate,默认情况下批量插入是关闭的,即使你调用save(Iterable),也是单条执行INSERT语句。如果中间某条失败,后面的就会终止,但前面的已经成功提交。
可以尝试开启批量插入优化,同时也能更清晰地看到批量操作的问题:
在application.properties/application.yml中添加配置:
spring.jpa.properties.hibernate.jdbc.batch_size=20 spring.jpa.properties.hibernate.order_inserts=true
总结
先从最基础的集合元素数量检查开始,再排查数据库约束,最后看事务和配置——按这个顺序排查,很快就能定位到问题。
内容的提问来源于stack exchange,提问作者sathvik vutukuri

