1. 程式人生 > >關於hibernate的 No row with the given identifier exists

關於hibernate的 No row with the given identifier exists

網上出現此問題大概原因有以下幾種:

  • 多對一配置中,一的一方資料不存在時報此異常
  • 雙向關聯的一方資料不存在時報此異常

但是我本地不是,我是多的一方資料不存在,廢話不多先上程式碼:


// 虛擬碼
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,即找不到的話就會丟擲異常。