hibernate的NonUniqueObjectException错误处理
具体描述:A different object with the same identifier value was already associated...问题的处理
网上的解释:
hibernate的session缓存之前处理过的数据,比如查询某些信息如User对象,当第二次查询时,从缓存中取出来就可以了。也正是因为session中缓存的存在,导致处理不当时,会出现问题。比如如下场景:
-
查出来来一个User对象,id为1,此时用户再new一个id为1的用户(id是用户的主键),执行save操作就会导致NonUniqueObjectException的异常,因为主键值相同,但是引用的对象不同。
-
执行更新的过程中也可能存在这样的问题,如下面的程序中(来自于互联网,未验证):
class A{}
class B{
private A many_to_one_A;
}
public void update_A_B(A a) {
B b=findByA(a);
update(b);
update(a);
}
错误原因:传进来的A是一个独立实体,加载B后,b对象会加载一个a在这个session中,如此在update(a)时,session重新加载并update,如此重复了。
解决办法:
public void update_A_B(A a) {
B b=findByA(a);
update(b);
a=b.getMany_to_one_A();
update(a);
}
除此之外,网上还给出了解决办法:
-
session.evict(objPO);或者在update之前session.clear();,清除缓存,或者调用evict方法,将当前对象设置为detached的状态
-
用session的merge方法,但是这个方法可能逻辑不对。
----------------------------------------------------分割线,上面来自互联网----------------------------
我今天说的是另一种情形,也是我犯的一个错误。
一个人拥有多个账户的情形
public class PersonTest implements Serializable{
private Long id;
private String userId;
private String name;
private Set<AccountTest> accountTests = new HashSet<AccountTest>(); //一个人对应多个账户
…//getter、setter
}
账户类:
public class AccountTest implements Serializable { private long id; //id private String userAccount;//用户账户 private PersonTest personTest; …//getter、setter }
配置文件
PersonTest类的文件
<class name="PersonTest" table="t_persontest"> <id name="id" type="long"> <generator class="increment"/> </id> <property name="name"> <column name="name" length="64" not-null="true"/> </property> <property name="userId"> <column name="userId" length="64" not-null="true"/> </property> <set name="accountTests" cascade="all" inverse="true"> <key column="personTest"></key> <one-to-many class="AccountTest"/> </set> </class>
AccountTest的配置文件
<class name="AccountTest" table="t_accountTest"> <id name="id" type="long" unsaved-value="null"> <generator class="increment"/> </id> <property name="userAccount"> <column name="userAccount" length="64" not-null="true"/> </property> <many-to-one name="personTest" class="PersonTest" column="personTest"> </many-to-one> </class>
测试程序
@Test public void testMany2oneDoubleAdd2() { session.beginTransaction(); //初始化用户 PersonTest pt = new PersonTest(); pt.setName("test1"); pt.setUserId("ttt"); AccountTest at1 = new AccountTest(); at1.setUserAccount("account1"); at1.setPersonTest(pt); pt.getAccountTests().add(at1); AccountTest at2 = new AccountTest(); at2.setUserAccount("account2"); at2.setPersonTest(pt); pt.getAccountTests().add(at2); session.save(pt); session.getTransaction().commit(); }
执行到save方法时报的错误如下:
A different object with the same identifier value was already associated with the session : [com.data.hibernate.prptyref.AccountTest#0]
…
其实也就是在save pt的时候,发现at1和at2中的id都已经被赋值了,且都是为0,因此出现了上述报错。
解决的方法也很简单,就是AccountTest的id由long变为Long。