org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identi

来源:互联网 发布:阿里云搭建游戏加速器 编辑:程序博客网 时间:2024/06/05 15:03

1、仅仅Hibernate情况

net.sf.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: .........
这样的问题不知道大家有没有遇到?
SessionFactory sessionFactory= new Configuration().configure().buildSessionFactory();
Session session=sessionFactory.openSession();
User user1=new User("anray");
User user2=new User("anray");
user1.setName("anray1");//假设User是一个持久对象,有一个name属性
user2.setName("anray2");
session.update(user1);
session.update(user2);
这样就会出现上面的异常
看上去上面的代码有点傻,我们编程中不可能出现这样的情况。
但是有一种情况是经常用到的,就是写一个专门的类来管理sessionFactory和session,如下
/*
* Examination System version 0.1
* Data persist layer(Using Hibernate 2.1.2)
* Created on 2004-4-9 11:58:12
*/
package bts.hibernate;
/**
* @author Anray
*/
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
public class HibernateUse 
{
   private static final SessionFactory sessionFactory;
   static {
     try {
       sessionFactory = new Configuration().configure().buildSessionFactory();
     } catch (HibernateException ex) {
       throw new RuntimeException("Exception building SessionFactory: " + ex.getMessage(), ex);
     }
   }
   public static final ThreadLocal threadLocal = new ThreadLocal();
  
   /**得到当前线程的session */
   public static final Session getSession() throws HibernateException {
     Session se = (Session) threadLocal.get();
     // Open a new Session, if this Thread has none yet
     if (se == null) {
       se = sessionFactory.openSession();
       threadLocal.set(se) ;
     }
     return se;
   }

   /**关闭当前线程的session */
   public static final void closeSession() throws HibernateException {
     Session s = (Session) threadLocal.get();
     threadLocal.set(null);
     if (s != null)
       s.close();
   }
  
   /**
   *保存一个对象到数据库中,使用完后要自己调用closeSession()
   */
   public static void create(Object object)
   throws HibernateException{
       Session session1 = getSession();
       Transaction transaction1 = session1.beginTransaction();
       try{
         session1.save(object);
         transaction1.commit();
        
       }catch(HibernateException ex){
         if(transaction1!=null)transaction1.rollback();
         closeSession();
         throw ex;
       }
   }
  
   /**
   *更新一个对象到数据库中,使用完后要自己调用closeSession()
   */
   public static void update(Object object)
   throws HibernateException{
     Session session1 = getSession();
     Transaction transaction1 = session1.beginTransaction();
     try{
       session1.update(object);
       transaction1.commit();
      
     }catch(HibernateException ex){
       if(transaction1!=null)transaction1.rollback();
       closeSession();
       throw ex;
     }
   }
}
如果在web编程时用这个类的方法来更新一个user对象,在调用了HibernateUse.update(user)后,没有接着调用HibernateUse.closeSession(),其实为了节省资源也不提倡每次操作都调用HibernateUse.closeSession()关闭session;如果对相同的user对象进行又一次的更新时,碰巧容器又分配了同一个thread进行处理,那么得到的也是同一个session,这样就出现了上面的提到了问题,session里的两个user的识别id一样,但内容不一样。

为了解决这个问题可以在,update前清空session(不是关闭,这样资源消耗比较少),修改后的公用类如下:(就是在update()方法里添加了session1.clear();)
/*
* Examination System version 0.1
* Data persist layer(Using Hibernate 2.1.2)
* Created on 2004-4-9 11:58:12
*/
package bts.hibernate;
/**
* @author Anray
*/
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
public class HibernateUse 
{
   private static final SessionFactory sessionFactory;
   static {
     try {
       sessionFactory = new Configuration().configure().buildSessionFactory();
     } catch (HibernateException ex) {
       throw new RuntimeException("Exception building SessionFactory: " + ex.getMessage(), ex);
     }
   }
   public static final ThreadLocal threadLocal = new ThreadLocal();
  
   /**得到当前线程的session */
   public static final Session getSession() throws HibernateException {
     Session se = (Session) threadLocal.get();
     // Open a new Session, if this Thread has none yet
     if (se == null) {
       se = sessionFactory.openSession();
       threadLocal.set(se);
     }
     return se;
   }

   /**关闭当前线程的session */
   public static final void closeSession() throws HibernateException {
     Session s = (Session) threadLocal.get();
     threadLocal.set(null);
     if (s != null)
       s.close();
   }
  
   /**
   *保存一个对象到数据库中,使用完后要自己调用closeSession()
   */
   public static void create(Object object)
   throws HibernateException{
       Session session1 = getSession();
       Transaction transaction1 = session1.beginTransaction();
       try{
         session1.save(object);
         transaction1.commit();
        
       }catch(HibernateException ex){
         if(transaction1!=null)transaction1.rollback();
         closeSession();
         throw ex;
       }
   }
  
   /**
   *更新一个对象到数据库中,使用完后要自己调用closeSession()
   */
   public static void update(Object object)
   throws HibernateException{
     Session session1 = getSession();
     Transaction transaction1 = session1.beginTransaction();
     try{
      session1.clear();
       session1.update(object);
       transaction1.commit();
     }catch(HibernateException ex){
       if(transaction1!=null)transaction1.rollback();
       closeSession();
       throw ex;
     }
   }
}

2、Spring中的Hibernate事务代理遇到该情况

参考:http://hi.baidu.com/fgfd0/blog/item/fe258935b74cee1790ef39ba.html

注意:我这里解决的是:org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identifier value was already associated with the session:

网上大多数解决的是 :net.sf.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:

他们也是有区别的,因为我用的是Spring中的Hibernate事务代理,来自动管理事务的。

Hibernate session中对象重复问题的解决方法(结合Spring应的Hibernate事务管理)

在网上查到的都是单针对Hibernate session对象重复的问题,没有查到在结合Spring事务代理时的Hibernate session对象重复问题的解决方法。
我遇到的问题是,我使用了org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator
所以在:下面的配置中userInfoService等service的事务都是自动的,OK自动事务是我想要的,我需要在对多个对象或多个表操作时在Service层的事务管理,
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
            <list>
            <value>userInfoService</value>
            <value>adminInfoService</value>
            <value>pageService</value>
            <value>companyInfoService</value>
            </list>
</property>
        <property name="interceptorNames">
            <list>
                <value>transactionInterceptor</value> 
            </list>
        </property>
    </bean>
但是有时会出现问题也就是:NonUniqueObjectException: a different object with the same identifier value was already associated with the session 异常。
并且经常会出现,这个异常很明显是因为Hibernate session出现了重复的对象,所以Hibernate不能同时更新两个拥有同一ID的对象。

具体详细问题我就不多说是怎么回事了可以看:http://www.cjsdn.com/post/view?bid=2&id=104169

下面是具体的解决方法:这个方法cAwardUpdateUserInfo,要求保存ui1和ui2并且查询他们的子如果他们有子对象责更新子。

public UserInfo cAwardUpdateUserInfo(UserInfo ui1, UserInfo ui2) {

   //最新修改的写法..... 也就是把所有的更新都放在最上面,下面的对象如果有改变Hibernate会自动更新他们,如果没改变Hibernate责不会管他。
   //这里为什么能解决问题我估计是因为手动调用update应该会自动清空session,所以这时session就不会有重复对象了,那下面的更新也就不用我们来管理了,并给Hibernate事务管理吧。
   this.saveUpUserInfo(ui1);
   this.saveUpUserInfo(ui2);


   //这里是出现问题的地方,也就是根据每个对象查出他们的子对象,如果有子对象就更新,
   //没子对象就不更新,所以假设查到子对象了,并更新了子对象。那它的父对象也能也更新。
   List ui1List = this.findUserInfoAllCAwardSub(ui1.getId()+"");
   List ui2List = this.findUserInfoAllCAwardSub(ui2.getId()+"");
  
    //开始 父子调换 
    int subFather    = ui1.getUiAwardCjFather();
    int subFatherCj = ui1.getUiAwardCj();
    int subFatherAdd = ui1.getUiAwardAddSum();
   
    ui1.setUiAwardCjFather(ui2.getUiAwardCjFather());
    ui1.setUiAwardCj(ui2.getUiAwardCj());
    ui1.setUiAwardAddSum(ui2.getUiAwardAddSum());
   
    if(ui2List!=null && ui2List.size()>=1){
     System.out.println("ui2List:"+ui2List.size());
     for(int i=0; i<ui2List.size(); i++){
      UserInfo tempSubUi = (UserInfo)ui2List.get(i);
      tempSubUi.setUiAwardCjFather(ui1.getId());
     }
    }

   
   
    ui2.setUiAwardCjFather(subFather);
    ui2.setUiAwardCj(subFatherCj);
    ui2.setUiAwardAddSum(subFatherAdd);
    if(ui1List!=null && ui1List.size()>=1){
     System.out.println("ui1List:"+ui1List.size());
     for(int i=0; i<ui1List.size(); i++){
      UserInfo tempSubUi = (UserInfo)ui1List.get(i);
      tempSubUi.setUiAwardCjFather(ui2.getId());
     }
    }
    return ui1;

// 下面是最起初 错误的写法。 
//    if((ui2List!=null && ui2List.size()>=1) && (ui1List!=null && ui1List.size()>=1)){
//     System.out.println("进入全不保存");
//     return ui1;
//    }
//   
//    if((ui1List!=null && ui1List.size()>=1) && (ui2List==null || ui2List.size()<=0)){
//     System.out.println("进入保存ui1");
//     //保存是否成功!
//     if(this.saveUpUserInfo(ui2)!=null){
//      return ui1;
//     }else{
//      return null;
//     }
//    }
//   
//    if((ui2List!=null && ui2List.size()>=1) && (ui1List==null || ui1List.size()<=0)){
//     System.out.println("进入保存ui2");
//     //保存是否成功!
//     if(this.saveUpUserInfo(ui1)!=null){
//      return ui1;
//     }else{
//      return null;
//     }
//
//    }
//   
//    System.out.println("进入全保存!");
//    //保存是否成功!
//    if(this.saveUpUserInfo(ui1)!=null && this.saveUpUserInfo(ui2)!=null){
//     return ui1;
//    }else{
//     return null;
//    }
}

原创粉丝点击