多次调用em.persist()失效:第三次persist操作无法执行
问题分析与解决方案
你的猜测不成立——第三次代码里明确new了全新的QuotaProductInfo实例,不存在共享VO的问题。下面是可能的原因和解决办法:
1. 先确认product2是否触发了执行逻辑
第三次persist被包裹在if(product2!=null)判断中,先排查:
product2是否为null,导致代码块根本没执行- 如果
product2是空字符串,null判断不会拦截,后续Integer.parseInt(qnt2_)可能抛出异常中断执行(若你没收到报错提示,优先确认是否进入了if块)
2. 检查事务提交逻辑
JPA的em.persist()只是将实体托管到持久化上下文,不会立即写入数据库,只有当事务提交或调用em.flush()时,数据才会落库。如果代码执行完没有提交事务,第三次的persist可能仅停留在内存中。
- 解决:
- 手动管理事务时,在所有
persist操作完成后调用em.getTransaction().commit() - 容器管理事务(如Spring环境),确保当前方法被
@Transactional注解修饰
- 手动管理事务时,在所有
3. maxSeq计算存在一致性与并发问题
你通过count(m)+1计算maxSeq的逻辑有明显问题:
- 第一次
persist(quotaInfo)后,事务未提交时,select count(m)可能读不到刚插入的记录(取决于事务隔离级别),导致maxSeq错误 - 并发场景下,多个请求同时插入会导致
quotaSeq重复
正确的做法是直接使用QuotaInfo的主键作为关联值:
em.persist(quotaInfo); // 如果主键是自增策略,persist后可直接获取(必要时调用em.flush()确保主键生成) Long maxSeq = quotaInfo.getId(); // 假设QuotaInfo的主键字段是id
4. 检查QuotaProductInfo的实体配置
- 确认实体的主键生成策略:如果主键是自增,不要手动设置主键值,否则可能导致插入失败
- 检查字段映射:确保
quotaSeq的@Column注解配置正确,没有拼写错误或类型不匹配 - 查看SQL日志:开启JPA的SQL打印,确认第三次插入的SQL是否执行,是否有约束冲突(如唯一索引重复)
修正后的示例代码
// 手动开启事务(按需) em.getTransaction().begin(); QuotaInfo quotaInfo = new QuotaInfo(); quotaInfo.setProject(project); quotaInfo.setSchool(school); quotaInfo.setRegion(region); quotaInfo.setSalesMan(salesMan); quotaInfo.setStat(stat); quotaInfo.setRegDate(LocalDateTime.now()); em.persist(quotaInfo); em.flush(); // 确保主键生成 Long maxSeq = quotaInfo.getId(); QuotaProductInfo quotaPInfo_1 = new QuotaProductInfo(); quotaPInfo_1.setName(product1); quotaPInfo_1.setQnt(qnt1); quotaPInfo_1.setPriceUnit(0); quotaPInfo_1.setQuotaSeq(maxSeq); em.persist(quotaPInfo_1); if(product2 != null && !product2.trim().isEmpty()) { QuotaProductInfo quotaPInfo_2 = new QuotaProductInfo(); quotaPInfo_2.setName(product2); int qnt2 = Integer.parseInt(qnt2_); quotaPInfo_2.setQnt(qnt2); quotaPInfo_2.setPriceUnit(0); quotaPInfo_2.setQuotaSeq(maxSeq); em.persist(quotaPInfo_2); } // 提交事务 em.getTransaction().commit();
内容的提问来源于stack exchange,提问作者JayCold
相关产品推荐
相关产品推荐

