了解hibernate中的NonUniqueObjectException

时间:2011-07-28 11:08:37

标签: java hibernate exception identifier

为了更多地了解Hibernate,我写了一些代码,它们创建了一些实体并将它们保存在db中,然后尝试删除其中一个实体。

实体Customer的映射文件将id生成器设置为native。我使用postgresql作为db。

...
<class name="Customer" table="CUSTOMER">
  <id column="CUSTOMER_ID" name="customer_id"  type="java.lang.Long">
  <generator class="native"/>
  </id>
...

我遇到了hibernate.NonUniqueObjectException。

 org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [org.me.hibernatestore.Customer#129]

完整堆栈跟踪here

我启动了eclipse调试器,发现所涉及的对象在所有涉及的方法中具有相同的地址。

代码的相关部分是

public class Main {
        CustomerDao custdao;
        Customer mark;
        public void storeDemo(){
           custdao = DaoFactory.getCustomerDao();
           createCustomers();
           updateEntities();
           deleteCustomer(mark);
        }
        private void createCustomers() {
            mark = new Customer();
            mark.setName("mark");
            mark.setEmailAddress("mark@home");
            mark.setAddress("121,3rd avenue");
            mark.setCity("San Diego");
            mark.setState("CA");
            mark.setCountry("U.S.A");
        }
        private  void updateEntities() {
            Transaction tx = null;
            Session session = HibernateUtil.getCurrentSession();        
            try{
                tx = session.beginTransaction();                
                custdao.saveOrUpdateCustomer(mark);
                tx.commit();
               }catch(RuntimeException e){          
            tx.rollback();
            throw e;
        }
       }
       private void deleteCustomer(Customer cust){
        Transaction tx = null;
        Session session = HibernateUtil.getCurrentSession();        
        try{
            tx = session.beginTransaction();            
            String custName = cust.getName();
            custdao.deleteCustomer(cust);
            tx.commit();            

        }catch(RuntimeException e){         
            tx.rollback();
            throw e;
        }
    }
        public static void main(String[] args)  {
        new Main().storeDemo();

    }
}

在调试器的帮助下,我找到了对象'mark'的地址

Main.createCustomers(): mark-> Customer@2bc3f5
CustomerDaoImpl.saveOrUpdateCustomer(Customer customer):customer-> Customer@2bc3f5
BaseDaoImpl.saveOrUpdate(T obj):obj-> Customer@2bc3f5

Main.deleteCustomer(Customer customer):customer-> Customer@2bc3f5
CustomerDaoImpl.deleteCustomer(Customer customer):customer-> Customer@2bc3f5
BaseDaoImpl.delete(T obj):obj-> Customer@2bc3f5

进一步尝试,我修改了代码并通过dao.findById()得到了一个具有相同id的不同对象,并在deleteCustomer()中使用了。这次代码工作没有抛出任何异常

public class Main {
        CustomerDao custdao;
        Customer mark;
        public void storeDemo(){
           custdao = DaoFactory.getCustomerDao();
           createCustomers();
           updateEntities();
           Long mark_id = mark.getCustomer_id();
           Customer mark2 = getCustomer(mark_id);
           deleteCustomer(mark2);
        }
    private Customer getCustomer(Long id){
        Transaction tx = null;
        Customer cust = null;
        Session session = HibernateUtil.getCurrentSession();

        try{
            tx = session.beginTransaction();
            return custdao.findCustomerById(id);

        }catch(RuntimeException e){         
            throw e;
        }
    }
        ...
}

有人可以解释一下这种行为吗?我对错误信息的'具有相同标识符值的不同对象'的理解是模糊的..在第一种情况下调试器中显示的对象有代码中到处都是相同的内存地址。那么它怎么可能是一个不同的对象?

真诚

吉姆

1 个答案:

答案 0 :(得分:0)

处理detached objects时通常会发生此异常。为了避免这种情况,您必须获取对象并在同一会话中将其删除,或者reattach将其删除到会话中,然后将其删除。 希望这有帮助!