2010-06-15 75 views
3

让我们看看一个简单的狗和猫朋友的例子。这并不罕见。它还有比我的商业案例更有趣的好处。了解休眠saveOrUpdate和持久生命周期

我们需要一个名为“saveFriends”的函数,它需要一个狗的名字和一个猫的名字。我们将保存狗和猫。为了这个例子的工作,猫将会有一个参考回到狗。我知道这不是一个理想的例子,但它很可爱,适用于我们的目的。

FriendService.java

public int saveFriends(String dogName, String catName) { 
    Dog fido = new Dog(); 
    Cat felix = new Cat(); 

    fido.name = dogName; 
    fido = animalDao.saveDog(fido); 

    felix.name = catName; 
    [ex.A]felix.friend = fido; 
    [ex.B]felix.friend = animalDao.getDogByName(dogName); 
    animalDao.saveCat(felix); 
} 

AnimalDao.java(延伸的HibernateDaoSupport)现在

public Dog saveDog(Dog dog) { 
    getHibernateTemplate().saveOrUpdate(dog); 
    return dog 
} 

public Cat saveCat(Cat cat) { 
    getHibernateTemplate().saveOrUpdate(cat); 
    return cat; 
} 

public Dog getDogByName(String name) { 
    return (Dog) getHibernateTemplate().find("from Dog where name=?", name).get(0); 
} 

,假设一分钟,我想为使用实施例A或例子B保存我的朋友。一个比另一个更好用吗?

此外,不会举例B让你臭名昭着的“非空属性引用空值或瞬态值”错误?我只是在这里猜测,但我会认为这是因为狗仍然在会议中。

我会理解这些例子是否都不起作用,但请解释原因。

+0

这些实体的标识符是什么? – mdma 2010-06-15 20:58:08

+0

@mdma我想我们可以说他们有通常的“id”字段作为标识符。 – Stephano 2010-06-15 22:27:45

+0

@Sephano - 谢谢 - 我不得不问 - 可能是因为名字被用作id--目前还不清楚saveFriends是否正在创建新的瞬变并持续它们,或者可能更新现有的持久实体(来自名称。 ) – mdma 2010-06-15 22:38:43

回答

4

现在,假设我想用例A或例B保存我的朋友一分钟。一个比另一个更好用吗?

两个例子就可以了(在例子B,Hibernate会flush the session before query executions所以它会插入之前选择狗),但我不认为做一个额外的选择(例如B)的时候你已经有狗实例。我会举个例子A.

此外,不会举例B让你臭名昭着的“非空属性引用空值或瞬态值”错误?

否(见上文)。在例子B中,狗不再是短暂的。在例A中,插入将按照正确的顺序完成。

我只是在这里猜测,但我会认为这是因为狗仍然在会议中。

第一级缓存(会话)用于通过id查找,在这里不是这种情况。

+0

+1非常好的答案。显然,我需要刷新缓存的级别。 – Stephano 2010-06-15 22:26:40

+0

你是对的,第一级缓存仅用于by-id查找,但在'felix.friend = animalDao.getDogByName(dogName)'后面,如果我没有记错,Hibernate保证'felix.friend == fido', RT? – 2010-06-15 23:04:06

+0

(假设'name'是'Dog'的一个独特属性) – 2010-06-15 23:05:24

2

从文档在hibernate

saveOrUpdate()方法执行以下操作:

如果对象是已持续在这个会议上,什么也不做

如果与会话相关的另一个对象有相同的标识符,抛出异常

如果对象没有标识符属性,则保存()它

如果对象的标识符具有分配给一个新实例化的对象的值,保存()它

如果对象是由一个或版本化,并且版本属性值是分配给一个新实例化的对象相同的值,保存()它

否则update()这个对象

明智的性能我想说分配参照对象,菲多点会更快,因为你没有打开到数据库的连接。

+0

+1往返的好处。根据您以前的建议,我改变了标题。我想我也很好奇Ex.2是否可以工作,或者自从该对象还在会话中之后会发生冲突? – Stephano 2010-06-15 20:14:58

+0

我相信会执行一次保存,因为既然“如果对象已经在这个会话中持久,什么也不做”,或者“如果与会话相关的另一个对象具有相同的标识符,抛出异常”在方法时为真调用。因此,这个对象将被保存。这当然可能是不正确的,但看着这个小片段,我相信这是正确的。 – Woot4Moo 2010-06-15 20:32:19

2

两者都能正常工作,但效率不高。在B之下,因为它执行查询,它不仅具有查询本身的开销,而且强制hibernate清除对数据库的更改 - 在事务被提交之前可能保留在内存中的更改,并与许多其他变化。

与db的连接通常会承受相当高的延迟,所以使用批处理一次发送很多更改,从而减少每个语句的延迟。将变更集分解为许多小的变更会导致每个语句的开销比一组更大的变更更高。所以,最好尽可能一起提交更改。

+0

关于“太早冲洗”的额外费用的好处。 +1 – 2010-06-16 07:36:26