關於hibernate的 No row with the given identifier exists

憶往昔思未來丶發表於2019-02-20

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

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

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


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

相關文章