有人知道Hibernate在调用session.saveOrUpdate()
时是如何知道INSERT还是更新数据库中的值?
到目前为止,我只确定它不依赖于缓存中的信息,并且数据库中实体的存在是由主键确定的。
答案 0 :(得分:38)
当你使用.saveOrUpdate()
时,Hibernate将检查对象是否是瞬态的(它没有标识符属性),如果是,它将通过生成标识符并将其分配给会话来使其持久化。如果对象已有标识符,则它将执行.update()
。
saveOrUpdate()执行以下操作:
答案 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)
如上所述here,saveOrUpdate
通过生成新标识符或更新/重新附加与其当前标识符关联的分离实例来保存瞬态实例。更具体地说:
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
}