網上出現此問題大概原因有以下幾種:
- 多對一配置中,一的一方資料不存在時報此異常
- 雙向關聯的一方資料不存在時報此異常
但是我本地不是,我是多的一方資料不存在,廢話不多先上程式碼:
// 虛擬碼
class Class{
@Id
Long id;
@OneToMany(cascade = CascadeType.DETACH,mappedBy = "clazz")
List<Student> students;
public Class(Map<String,Object> param){
// 構建新的物件
Class newClazz = new Class();
newClazz.setId((Long)param.get("id"));
// 構建新的學生物件
List<Map<String,Object>> studentMaps = param.get("students");
students = new ArraryList();
studentMaps.forEach(map -> {
Student st = new Student();
st.setId((Long)map.get("id"));
students.add(st);
})
}
}
class Student{
@Id
Long id;
@ManyToOne(cascade = CascadeType.DETACH)
@JoinColumn(name="class_id")
Class clazz;
}
複製程式碼
以上是實體類對應的為虛擬碼,接下來是業務操作:
class ClassManagerImpl implements IClassManager{
void saveOrUpdate(Map<String,Object> params){
Class newClass = new Class(params);
Class oldClass = classDao.get(newClass.getId());
if(oldClass!=null){
newClass.setCreateDate(oldClass.getCreateDate());
}
classDao.saveOrUpdate(newClass);
}
}
class ClassDaoImpl implements IClassDao{
void saveOrUpdate(Class class){
try {
this.hibernateTemplate.saveOrUpdate(class);
} catch (DuplicateKeyException | NonUniqueObjectException e) {
// 此處merge報出以上bug
this.hibernateTemplate.merge(obj);
}
}
}
複製程式碼
以上的程式碼,在出現以下這種情況:
Class已存在,但是他關聯的Student物件不存在
會報兩個錯:
- A different object with the same identifier value was already associated with the session
- No row with the given identifier exists
出現第一個問題是由於呼叫saveOrUpdate()時由於我們呼叫get方法時已查詢過一次Class物件,但是我們更新時又是建立的新物件,所以會報錯。
出現第二個問題的原因是因為我們捕獲了第一個異常:NonUniqueObjectException,然後呼叫merge()方法,merge方法用於合併屬性,當我們有一對多等關聯配置時,他會去資料庫查詢相應的資料來進行資料合併,如果關聯資料不存在就會出錯。
舉例:
id為1的Class 存在資料庫中,此處資料庫中還沒有Student資料。我們通過業務更新ID為1的Class,同時新增一個Student物件。此時就會報錯
解決辦法為增加not-found配置:
註解方式:
class Class{
@Id
Long id;
@OneToMany(cascade = CascadeType.DETACH,mappedBy = "clazz")
@NotFound(action= NotFoundAction.IGNORE)
List<Student> students;
}
複製程式碼
XML配置方式:
<class name="Class" table="class">
<id column="id" name="id" type="java.lang.Long"><generator class="assigned" /></id>
<bag name="students" cascade="none">
<key>class_id</key>
<one-to-many not-found="ignore" class="Student" />
</bag>
</class>
複製程式碼
該引數預設為EXCEPTION,即找不到的話就會丟擲異常。