欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

hibernate的NonUniqueObjectException错误处理

程序员文章站 2022-07-11 20:15:16
...

 

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

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