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

标签 hibernate jakarta-ee orm

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

来自javadoc :

get():

Return the persistent instance of the given entity class with the given identifier, or null if there is no such persistent instance. (If the instance is already associated with the session, return that instance. This method never returns an uninitialized instance.)

加载():

Return the persistent instance of the given entity class with the given identifier, assuming that the instance exists. This method might return a proxied instance that is initialized on-demand, when a non-identifier method is accessed.

我有三个问题:

  1. javadoc 没有说明 load() 何时可能返回代理 - 有什么方法可以提前知道它吗?

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

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

谢谢!

更新

下面的说法正确吗?

(A) 我认为 load()get() 在访问数据库之前都会首先尝试检查 session 缓存 - 所以这是不对的说它们中的任何一个总是访问数据库,或者总是返回代理。

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

最佳答案

(1)、(3):

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

如果是,则仅从 session 中返回该实例。 (可能是代理,也可能是实际的实体类实例)

如果没有,load()将创建并返回一个代理,而get()将访问数据库并返回实际实体类的实例。

这两个方法返回的对象将被关联并保留在 session 中。

因此,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值的 session 被关联。

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

例如:

/**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() 并检查返回的实例是否为 null 。 load() 在设置外键约束时很有用。请参阅this

关于Hibernate 3.6 - session.get() 与 session.load(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8044963/

相关文章:

java - Hibernate 将 NULL 时间戳解释为当前日期/时间

php - ORM:友谊/好友关系

django 之间的区别 - 一对一、多对一和多对多

java - 使用 Hibernate 计算和存储预先计算的平均值

hibernate - 使用延迟初始化属性分离 JPA 对象

java - Hibernate、MySQL、Spring MVC、Freemarker :java. sql.SQLSyntaxErrorException:您的 SQL 语法有错误

java - 玻璃鱼 3.1.1 : Retrieve HTTP-Authentication in RESTful Webservice

Java EE 规范和多线程

java - 哪些 SOAP 库可用于 Google App Engine?

java - Hibernate NameGenerator 中带有 hql 查询的 NullpointerException