hibernate的NonUniqueObjectException错误处理

阅读更多

 

具体描述:A different object with the same identifier value was already associated...问题的处理 

网上的解释: 

hibernate的session缓存之前处理过的数据,比如查询某些信息如User对象,当第二次查询时,从缓存中取出来就可以了。也正是因为session中缓存的存在,导致处理不当时,会出现问题。比如如下场景: 

  1. 查出来来一个User对象,id1,此时用户再new一个id1的用户(id是用户的主键),执行save操作就会导致NonUniqueObjectException的异常,因为主键值相同,但是引用的对象不同。

  2. 执行更新的过程中也可能存在这样的问题,如下面的程序中(来自于互联网,未验证):

      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);  

  

除此之外,网上还给出了解决办法:

  1. session.evict(objPO);或者在update之前session.clear();,清除缓存,或者调用evict方法,将当前对象设置为detached的状态

  2. sessionmerge方法,但是这个方法可能逻辑不对。

----------------------------------------------------分割线,上面来自互联网----------------------------

我今天说的是另一种情形,也是我犯的一个错误。 

一个人拥有多个账户的情形 

public class PersonTest implements Serializable{
    private Long id;
    private String userId;
    private String name;
    private Set accountTests = new HashSet(); //一个人对应多个账户
…//getter、setter
} 

账户类: 

public class AccountTest implements Serializable {
    private long id; //id
    private String userAccount;//用户账户
    private PersonTest personTest;
    …//getter、setter
} 

配置文件 

PersonTest类的文件 

name="PersonTest" table="t_persontest">
    name="id" type="long">
        class="increment"/>
    
    name="name">
        name="name" length="64" not-null="true"/>
    
    name="userId">
        name="userId" length="64" not-null="true"/>
    
     name="accountTests"  cascade="all" inverse="true">
        column="personTest">
        class="AccountTest"/>
    

 AccountTest的配置文件 

name="AccountTest" table="t_accountTest">
    name="id" type="long" unsaved-value="null">
        class="increment"/>
    
    name="userAccount">
        name="userAccount" length="64" not-null="true"/>
    
      name="personTest" class="PersonTest" column="personTest">
    

 测试程序 

@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的时候,发现at1at2中的id都已经被赋值了,且都是为0,因此出现了上述报错。

解决的方法也很简单,就是AccountTestidlong变为Long

你可能感兴趣的:(hibernate)