首先我想吐槽一下这JPA报错得很奇怪,按照堆栈信息,把我引入到了一个不相干的地方,后来大胆推论,才发现真实的报错点,原来时JPA的更新时由于级联关系而抛出的错误。
实体类DataSetDef中,对fieldDefs这个属性的定义如下,
/**
* 字段定义
*/
@OneToMany(mappedBy = "dataSetDef", fetch=FetchType.EAGER,cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE }, orphanRemoval = true)
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@JsonIgnoreProperties(allowSetters = true, value = { "createdBy" })
@OrderBy("ORD")
@Fetch(FetchMode.SUBSELECT)
private List<FieldDef> fieldDefs;
配置项cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE },意思为DataSetDef和fieldDefs级联新建、级联更新、级联删除。
报错处的语法是:
dataSetDef的List< FieldDef >是一个持久的集合存在hibernate的对象池里面,如果直接dataSetDef.setFieldDefs(newFields);;就把dataSetDef对FieldDef对象的引用指向hibernate对象池外了。
我们需要修改这个集合而不是重新指定一个新的集合到parent类中。
改动如下,问题解决:
法一、在业务代码中修改红框部分为:
if(dataSetDef.getFieldDefs() != null){
dataSetDef.getFieldDefs().clear();
dataSetDef.getFieldDefs().addAll(newFields);
}else{
dataSetDef.setFieldDefs(newFields);
}
法二、在dataSetDef的实体类中重写setFieldDefs方法:
public void setFieldDefs(List<FieldDef> newFields){
this.fieldDefs.clear();
this.fieldDefs.addAll(newFields);
}