Java Play 1.44/JPA更新BEntity时新增行问题原因及修改方案咨询
问题根因
- 操作的BEntity未携带原有主键:BEntity主键使用
@GeneratedValue(strategy = GenerationType.IDENTITY)自增策略,且主键类型为包装类Integer,默认值为null。当JPA检测到实体主键为null时,会判定为全新实体,执行insert操作而非update。 - 未复用持久态对象:你在AEntity的
@OneToOne关联上配置了cascade = CascadeType.ALL,如果修改时直接给AEntity的bEntity字段赋值新构造的BEntity对象,而非先查询出已关联的原有BEntity对象再修改字段,级联操作会将无主键的新对象判定为待插入数据。
修复方案
方案1:优先复用持久态BEntity(推荐)
修改BEntity字段前,先从持久化上下文中查询出已关联的原有BEntity对象,修改字段后再保存,示例代码如下:
// 错误写法:直接构造新对象赋值,会触发插入 AEntity a = AEntity.findById(aId); BEntity newB = new BEntity(); newB.setBEntry("修改后的值"); a.setBEntity(newB); a.save(); // 正确写法:复用已有持久态对象,触发更新 AEntity a = AEntity.findById(aId); BEntity existB = a.getBEntity(); existB.setBEntry("修改后的值"); a.save();
方案2:游离对象更新需携带原有主键
如果业务逻辑需要使用游离对象更新,必须显式设置原有BEntity的主键值,示例代码如下:
AEntity a = AEntity.findById(aId); BEntity updateB = new BEntity(); // 必须携带原有主键,JPA才会判定为待更新实体 updateB.setId(a.getBEntity().getId()); updateB.setBEntry("修改后的值"); a.setBEntity(updateB); a.save();
可选优化配置
可以给BEntity新增乐观锁@Version字段,既可以避免并发更新冲突,也能辅助JPA更准确判断实体状态:
@Entity @Table(name = "BTable") public class BEntity extends GenericModel { // 原有字段不变 @Version private Integer version; }
内容的提问来源于stack exchange,提问作者Pradyot Dhulipala
相关产品推荐
相关产品推荐

