Hibernate saveOrUpdate行为

时间:2011-06-22 17:00:59

标签: java database hibernate

有人知道Hibernate在调用session.saveOrUpdate()时是如何知道INSERT还是更新数据库中的值?

到目前为止,我只确定它不依赖于缓存中的信息,并且数据库中实体的存在是由主键确定的。

5 个答案:

答案 0 :(得分:38)

当你使用.saveOrUpdate()时,Hibernate将检查对象是否是瞬态的(它没有标识符属性),如果是,它将通过生成标识符并将其分配给会话来使其持久化。如果对象已有标识符,则它将执行.update()

来自documentation

saveOrUpdate()执行以下操作:

  • 如果对象已经持久化 在这个会话中,什么都不做
  • 如果另一个对象与...相关联 session具有相同的标识符, 抛出异常
  • 如果对象没有标识符 property,save()it
  • 如果对象的标识符有 分配给新的值 实例化对象,save()它
  • 如果对象是由a版本化的  或者,和 版本属性值是相同的 分配给新的值 实例化对象,save()它 否则更新()对象

答案 1 :(得分:9)

引用Hibernate圣经(Java Persistence with Hibernate, 2nd ed.,第528页)可能会有所帮助:

  

更有经验的Hibernate用户只使用saveOrUpdate();让Hibernate决定什么是新的和什么是旧的更容易,特别是在具有混合状态的更复杂的对象网络中。排除saveOrUpdate()的唯一(不是非常严重)缺点是,如果没有在数据库中触发SELECT,它有时无法猜测实例是旧的还是新的 - 例如,当映射类时使用自然复合键,没有版本或时间戳属性。

     

Hibernate如何检测哪些实例是旧的,哪些是新实例?有多种选择。 Hibernate假定实例是未保存的瞬态实例,如果:

     
      
  • 标识符属性为null
  •   
  • 版本或时间戳属性(如果存在)为null
  •   
  • 由Hibernate在内部创建的同一持久化类的新实例具有与给定实例相同的数据库标识符值。
  •   
  • 您在类的映射文档中提供unsaved-value,并且identifier属性的值匹配。 unsaved-value属性也可用于版本和时间戳映射元素。
  •   
  • 具有相同标识符值的实体数据不在二级缓存中。
  •   
  • 在检查代码中的实例后,您提供了一个实现或org.hibernate.Interceptor并从Boolean.TRUE返回Interceptor.isUnsaved()
  •   

答案 2 :(得分:2)

如上所述heresaveOrUpdate通过生成新标识符或更新/重新附加与其当前标识符关联的分离实例来保存瞬态实例。更具体地说:

  • 如果该对象在此会话中已经持久化,则不执行任何操作
  • 如果与会话关联的另一个对象具有相同的标识符,则抛出异常
  • 如果对象没有标识符属性,save()
  • 如果对象的标识符具有分配给新实例化对象的值,则保存()它
  • 如果对象由<version><timestamp>版本化,且版本属性值为
  • 分配给新实例化对象的相同值save()
  • 否则update()对象

答案 3 :(得分:1)

这是基于主键的值完成的。如果主键未定义,则对于数字代理键,其值将默认为0,并且将执行save。如果填写了主键,它将调用update

答案 4 :(得分:1)

如果某人在理论上没有真正理解,那么就有一个代码

MyModel sent = myDao.myDaoImpl(id); 

if(sent == null){                        
    sent = **new MyModel();** // new Object
    sent.setXX(id);
    sent.setYY("Yes");
    sent.setDate(new Date());
    myDao.saveOrUpdate(sent); // Insert will be called
} else if(! "Yes".equalsIgnoreCase(sent.getFlag())) {
    sent.setXX("Yes");
    sent.setDate(new Date());
    myDao.saveOrUpdate(sent); // Update will be called
}