2011-11-08 45 views
9

我想了解什么区别是在返回的对象和行为的休眠3.6 session.get()session.load()Hibernate 3.6 - session.get()vs session.load()

javadoc

get()方法:

返回与 指定的标识符,或者,如果不存在这样的持久化实例空给定的实体类的持久化实例。 (如果 的实例已经与会话相关联,返回 例如该方法不会返回一个未初始化的实例。)

负载():

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

我有三个问题:

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

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

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

谢谢!

UPDATE

是以下是否正确?(A)我认为load()get()将首先尝试检查会话高速缓存之前去DB - 所以它不会是正确的说,他们中的任何总是命中数据库,或总是返回一个代理。

(B)的初始化代理是不一样的原始实例,你可以在这里阅读:http://blog.xebia.com/2008/03/08/advanced-hibernate-proxy-pitfalls/

回答

17

(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()访问DB .The代理将只访问DB如果除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

+0

1。但是如果我在会话中已经有一个初始化的实例(对于这个ID),它是不是会返回该实例,而不是代理?此外,javadoc说:“这种方法可能会返回一个代理实例” - 它不会说“这个方法将永远”。 2.这是一种设计缺陷 - 因为根据你的说法,当我有一个代理,我想确保它代表一个实际的数据库中的数据库(我总是想确保 - 即使我只使用代理指向其他实例) - 然后我不知道我使用的ID是有效的,直到我初始化它,但在这种情况下,为什么使用代理? – rapt

+0

3.你的意思是'load()'在'load()'后面会返回一个初始化的代理,或者只是一个初始化的实例?因为如果它是后者,那么我们现在在会话中有两个对象拥有相同的ID(代理和实例)。顺便说一句,我知道有可能有两个代理代表相同的数据库ID - 你可以在这里阅读:http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/在文本“其次,有可能破坏代理“。 - 在我的原始问题更多的更新。 – rapt

+0

是的。你是对的。你的问题帮助我清除了一些关于'get()'和'load()'的误解。看到我的更新请 –

相关问题