Hibernate的merge()方法

 

还是好久以前接触过hibernate,公司的项目一直用ibatis,昨天做外面的项目时碰到一个问题:

    

   laborPerson.setId(laborPersonId);
   ...
   LaborPerson oldLaborPerson = (LaborPerson)getDao().getObjById(LaborPerson.class, laborPersonId);
   laborPerson.setCreateTime(oldLaborPerson.getCreateTime());
   laborPerson.setCreateUser(oldLaborPerson.getCreateUser());
   laborPerson.setUnit(oldLaborPerson.getUnit());
   oldLaborPerson = null;


saveOrupdate时报错 a different object with the same identifier value was already associated with the session

其实只是想修改时保存原来老数据的创建时间之类的字段,朋友说叫我取出老数据后一个一个set进去,几十个字段啊,想想以前好像有方法可以合并的,找了篇文章试一下,可以正常了更新了(不用saveOrupdate了,直接按laborPersonId判断是插入还是更新,更新就用merge),hibernate继续摸索中...

 

  if(StringUtil.isNotNullOrBlank(laborPersonId))
  {
      LaborPerson oldLaborPerson = (LaborPerson)getDao().getObjById(LaborPerson.class, laborPersonId);
      laborPerson.setCreateTime(oldLaborPerson.getCreateTime());
      laborPerson.setCreateUser(oldLaborPerson.getCreateUser());
      ...    
      HibernateUtil.getSession().merge(laborPerson);
   }
   else 
   {
      laborPerson.setCreateTime(new Date());
      laborPerson.setCreateUser(curUser);
      ...       
      HibernateUtil.getSession().save(laborPerson);
   }

 

 

 

原文:http://littie1987.iteye.com/blog/1039082

Hibernate的merge()方法

      下面来讲讲Hibernate的merge方法。我打算按照hibernate对象生命周期的三个状态来讲。

1:如果POJO对象处于游离态,我所说的游离态是指该对象的id值为空。hibernate判断一个对象在数据库中是否存在不是看对象的其他信息,而是判断该id在数据库中是不是存在。如果id为空,那自然是不存在,所以当我们调用merge方法的时候,就会直接执行插入操作。这一点有点像saveorupdate()方法。看一段代码:

Java代码
  1. User user = new User();   
  2. //user.setId(4);   
  3. user.setUsername("heyuanling2");   
  4. user.setAge(23);   
  5. user.setSex("w");   
  6. user.setPassword("heyuanling");   
  7. Session session = this.getSession();   
  8. Transaction tr = session.beginTransaction();   
  9. //User exituser = (User)session.get(User.class, new Integer(1));   
  10. session.merge(user);   
  11. tr.commit();  
		User user = new User();
		//user.setId(4);
		user.setUsername("heyuanling2");
		user.setAge(23);
		user.setSex("w");
		user.setPassword("heyuanling");
		Session session = this.getSession();
		Transaction tr = session.beginTransaction();
		//User exituser = (User)session.get(User.class, new Integer(1));
		session.merge(user);
		tr.commit();

 

再看hibernate的sql语句:

Java代码
  1. Hibernate:    
  2.     select   
  3.         max(id)    
  4.     from   
  5.         user_   
  6. Hibernate:    
  7.     insert    
  8.     into   
  9.         user_   
  10.         (username, password, sex, age, birthday, other, id)    
  11.     values   
  12.         (?, ?, ?, ?, ?, ?, ?)  
Hibernate: 
    select
        max(id) 
    from
        user_
Hibernate: 
    insert 
    into
        user_
        (username, password, sex, age, birthday, other, id) 
    values
        (?, ?, ?, ?, ?, ?, ?)

 

二:脱管态:如果我们把上面代码里//user.setId(4);的注释去掉,那么它就变成了脱管的对象了(其实从游离到脱管就这么简单,没有官方说的那么邪乎...)。这是我们再来看控制台的sql打印:

Java代码
  1. Hibernate:    
  2.     select   
  3.         user0_.id as id4_0_,   
  4.         user0_.username as username4_0_,   
  5.         user0_.password as password4_0_,   
  6.         user0_.sex as sex4_0_,   
  7.         user0_.age as age4_0_,   
  8.         user0_.birthday as birthday4_0_,   
  9.         user0_.other as other4_0_    
  10.     from   
  11.         user_ user0_    
  12.     where   
  13.         user0_.id=?  
Hibernate: 
    select
        user0_.id as id4_0_,
        user0_.username as username4_0_,
        user0_.password as password4_0_,
        user0_.sex as sex4_0_,
        user0_.age as age4_0_,
        user0_.birthday as birthday4_0_,
        user0_.other as other4_0_ 
    from
        user_ user0_ 
    where
        user0_.id=?

 看到没有,因为id不为空了,所以hibernate就不会再insert了。由于该对象的信息和数据库里的一模一样,所以hibernate只执行了一个select语句,并没有update,如果我们把字段的值做稍微的变动,那么控制台打印的sql语句还应该有一条update语句。就这一点来说,merge还有和saveorupdate()方法一样。

 

 

三:持久态:持久态更好理解。如果我们从数据库里get一条记录,那么这条记录就处于持久态,如果再调用merge,那么hibernate就会先判断该记录是否被修改,没有则什么也不干,修改了就update。这一点还是和saveorupdate()有点像。

Java代码
  1. Session session = this.getSession();   
  2. Transaction tr = session.beginTransaction();   
  3. User exituser = (User)session.get(User.classnew Integer(1));   
  4. exituser.setAge(11);   
  5. session.merge(exituser);   
  6. tr.commit();   
  7. session.close();  
Session session = this.getSession();
Transaction tr = session.beginTransaction();
User exituser = (User)session.get(User.class, new Integer(1));
exituser.setAge(11);
session.merge(exituser);
tr.commit();
session.close();

 再看控制台打印结果:

Java代码
  1. Hibernate:    
  2.     select   
  3.         user0_.id as id4_0_,   
  4.         user0_.username as username4_0_,   
  5.         user0_.password as password4_0_,   
  6.         user0_.sex as sex4_0_,   
  7.         user0_.age as age4_0_,   
  8.         user0_.birthday as birthday4_0_,   
  9.         user0_.other as other4_0_    
  10.     from   
  11.         user_ user0_    
  12.     where   
  13.         user0_.id=?   
  14. Hibernate:    
  15.     update   
  16.         user_    
  17.     set   
  18.         username=?,   
  19.         password=?,   
  20.         sex=?,   
  21.         age=?,   
  22.         birthday=?,   
  23.         other=?    
  24.     where   
  25.         id=?  
Hibernate: 
    select
        user0_.id as id4_0_,
        user0_.username as username4_0_,
        user0_.password as password4_0_,
        user0_.sex as sex4_0_,
        user0_.age as age4_0_,
        user0_.birthday as birthday4_0_,
        user0_.other as other4_0_ 
    from
        user_ user0_ 
    where
        user0_.id=?
Hibernate: 
    update
        user_ 
    set
        username=?,
        password=?,
        sex=?,
        age=?,
        birthday=?,
        other=? 
    where
        id=?

  如果没有对记录进行修改则不会有后面的那条update语句。

 

那么merge和saveorupdate()到底有什么区别呢?看一段代码:

Java代码
  1. Session session = this.getSession();   
  2. Transaction tr = session.beginTransaction();   
  3. User exituser = (User)session.get(User.classnew Integer(1));   
  4. tr.commit();   
  5. session.close();   
  6. session = getSession();   
  7. tr = session.beginTransaction();   
  8. User exituser2 = (User)session.get(User.classnew Integer(1));   
  9. session.update(exituser);   
  10. tr.commit();   
  11. session.close();  
Session session = this.getSession();
Transaction tr = session.beginTransaction();
User exituser = (User)session.get(User.class, new Integer(1));
tr.commit();
session.close();
session = getSession();
tr = session.beginTransaction();
User exituser2 = (User)session.get(User.class, new Integer(1));
session.update(exituser);
tr.commit();
session.close();

 运行上面的代码,hibernate给我们报了一个错误:a different object with the same identifier value was already associated with the session。意思是,在session缓存中以两个标识相同的对象,这是不可以的。那么,吧update改成merge会怎么样呢?改为merge后,一切OK,运行正常。其实merge在执行更新之前会将两个标识符相同的对象进行合并,具体合并的方向是向exituser2合并。

 

注意:merge方法在执行之前都回去缓存中找是不是有相应的记录,也就是会有一条select语句,执行改语句的目的是为了判断该对象是否被修改了。而update就不管这些,直接就一条update语句。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值