我试图了解Hibernate 3.6 session.get()
和session.load()
的返回对象和行为的区别。
来自javadoc:
get():
返回给定实体类的持久化实例 给定标识符,如果没有这样的持久化实例则为null。 (如果 实例已经与会话关联,返回该实例 实例。此方法永远不会返回未初始化的实例。)
load():
返回给定实体类的持久化实例 给定标识符,假设实例存在。这个方法可能会 当a时,返回按需初始化的代理实例 访问非标识符方法。
我有三个问题:
javadoc没有说明load()
何时可能会返回代理 - 有没有办法提前知道?
当load()
返回代理时 - 这意味着load()
没有访问数据库,我是否正确?那么如果我为load()
提供了数据库中不存在的标识符呢?我现在将在会话中拥有一个具有无效ID的代理(没有获得异常)。现在我想让另一个持久化实例指向该代理 - 它会起作用吗?对于这种情况,我不需要初始化代理,我只需要它的id(即使它是无效的,因为它不在数据库中)。所以我想我问的是我的描述是否正确,并且我总是需要在load()
返回的对象isInitialized()
之后签出,以确保它代表一个有效的实体(或者至少是有效的代理人),即有效的身份证。
此外,如果load()
返回代理,会发生什么 - 因此代理是已与会话关联的实例。然后根据get()
的描述:“如果实例已经与会话关联,则返回该实例。” - get()
也会返回代理吗?因为根据get()
的描述:“此方法永远不会返回未初始化的实例。”
谢谢!
更新
以下是否正确?
(A)我认为load()
和get()
在转到数据库之前会首先尝试检查会话缓存 - 所以说任何一个总是命中数据库是不对的,或总是返回代理。
(B)初始化代理与原始实例不同,您可以在此处阅读:http://blog.xebia.com/2008/03/08/advanced-hibernate-proxy-pitfalls/
答案 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