Hibernate 3.6 - session.get()vs session.load()

时间:2011-11-08 01:32:39

标签: hibernate java-ee orm

我试图了解Hibernate 3.6 session.get()session.load()的返回对象和行为的区别。

来自javadoc

get():

  

返回给定实体类的持久化实例   给定标识符,如果没有这样的持久化实例则为null。 (如果   实例已经与会话关联,返回该实例   实例。此方法永远不会返回未初始化的实例。)

load():

  

返回给定实体类的持久化实例   给定标识符,假设实例存在。这个方法可能会   当a时,返回按需初始化的代理实例   访问非标识符方法。

我有三个问题:

  1. javadoc没有说明load()何时可能会返回代理 - 有没有办法提前知道?

  2. load()返回代理时 - 这意味着load()没有访问数据库,我是否正确?那么如果我为load()提供了数据库中不存在的标识符呢?我现在将在会话中拥有一个具有无效ID的代理(没有获得异常)。现在我想让另一个持久化实例指向该代理 - 它会起作用吗?对于这种情况,我不需要初始化代理,我只需要它的id(即使它是无效的,因为它不在数据库中)。所以我想我问的是我的描述是否正确,并且我总是需要在load()返回的对象isInitialized()之后签出,以确保它代表一个有效的实体(或者至少是有效的代理人),即有效的身份证。

  3. 此外,如果load()返回代理,会发生什么 - 因此代理是已与会话关联的实例。然后根据get()的描述:“如果实例已经与会话关联,则返回该实例。” - get()也会返回代理吗?因为根据get()的描述:“此方法永远不会返回未初始化的实例。”

  4. 谢谢!

    更新

    以下是否正确?

    (A)我认为load()get()在转到数据库之前会首先尝试检查会话缓存 - 所以说任何一个总是命中数据库是不对的,或总是返回代理。

    (B)初始化代理与原始实例不同,您可以在此处阅读:http://blog.xebia.com/2008/03/08/advanced-hibernate-proxy-pitfalls/

1 个答案:

答案 0 :(得分:18)

(1),(3):

是。你是对的。load()get()将首先检查会话中是否存在具有相同PK的实例。

如果是,则只从会话中返回该实例。 (它可能是代理或实际的实体类实例)

如果不是,load()将创建并返回代理,而get()将命中DB并返回实际实体类的实例。

两个方法中返回的对象将在之后的会话中关联并保留。

因此,get()load()返回代理还是实际实体类取决于您是使用get()还是load()来获取当前会话中相同PK的实例第一次。

您可以通过执行以下测试来证明此行为:

Session session = HibernateUtil.getSessionFactory().openSession();

Item loadItem= (Item ) session.load(Item.class, 1);
System.out.println(loadItem.getClass().getName());

Item getItem = (Item ) session.get(Item .class, 1);
System.out.println(getItem .getClass().getName());

如果是代理,则打印的类名称将与实际的实体类名称不同。只需将执行顺序更改为load()get()即可查看效果。

(2):

如果load()返回代理,它将不会在load()期间访问数据库。如果访问了除PK之外的映射属性并且没有具有相同PK值的实例,代理将只访问数据库与会话相关联。

代理访问数据库后,具有相同代理PK的实例将与该会话关联。因此,当您再次从代理获取另一个属性或使用get()获取实例时相同的PK,不会访问数据库,因为可以从会话中找到值。

例如:

/**Session starts***/
Item item = (Item) session.load(Item.class, new Long(1));
item.getId();  //Will not access DB as only the identifier property is access
item.getDescription(); // access the DB and initialize the proxy . After that , the item proxy is said to be initialized
item.getPrice(); //will not access DB as the item with the PK 1 can be get from the session
Item item2 = session.get(Item.class, new Long(1)) //will not access DB as the item with the PK 1 can be get from the session

如果load()具有无效ID的实例然后在此代理上访问属性或调用方法(例如isInitialized()),则会引发ObjectNotFoundException。因此,如果您可以捕获ObjectNotFoundException,则表示代理加载了无效ID。

如果要确保ID在运行时有效,则应使用get()并检查返回的实例是否为空。设置外键约束时load()非常有用。见this