网上出现此问题大概原因有以下几种:
但是我本地不是,我是多的一方数据不存在,废话不多先上代码:
// 伪代码 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对象不存在
会报两个错:
出现第一个问题是由于调用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,即找不到的话就会抛出异常。