【发布时间】:2011-07-19 05:37:46
【问题描述】:
谁能告诉我在 Hibernate 中 load() 与 get() 的优势是什么?
【问题讨论】:
谁能告诉我在 Hibernate 中 load() 与 get() 的优势是什么?
【问题讨论】:
| load() | get() |
|---|---|
Only use load() method if you are sure that the object exists. |
If you are not sure that the object exist, then use one of get() methods. |
load() method will throw an exception if the unique id is not found in the database. |
get() method will return null if the unique id is not found in the database. |
load() just returns a proxy by default and database won't be hit until the proxy is first invoked. |
get() will hit the database immediately. |
代理意味着,hibernate 会在内存中准备一些具有给定标识符值的假对象,而不会访问数据库。
例如:
如果我们打电话给session.load(Student.class,new Integer(107));
hibernate 会在内存中创建一个 id 为 107 的假 Student 对象 [row],但 Student 类的剩余属性甚至不会被初始化。
【讨论】:
Get() 通过从数据库或休眠缓存中获取对象来返回对象,而 load() 仅返回可能实际不存在的对象的引用,它仅在您访问其他属性时才从数据库或缓存中加载数据对象。
使用 load(),我们可以打印 id,但是一旦我们尝试访问其他字段,它就会触发数据库查询并在没有找到具有给定标识符的记录时抛出 org.hibernate.ObjectNotFoundException。它是休眠特定的运行时异常,因此我们不需要显式捕获它。
【讨论】:
session.load(): 它将始终返回具有给定标识值的代理对象,即使该标识值在数据库中不存在。但是,当您尝试通过从数据库中检索代理的属性来初始化代理时,它将使用 select 语句访问数据库。如果没有找到行,则会抛出 ObjectNotFoundException。
session.get(): 如果在数据库中找不到标识值,它将始终返回 null 。
【讨论】:
性能问题也是get和load方法的主要区别。
get() 方法一执行就获取数据,而 load() 方法返回一个代理对象,并且只在需要对象属性时获取数据。 这样 load() 方法获得了更好的性能,因为它支持延迟加载。 只有当我们知道数据存在时才应该使用 load() 方法,因为当找不到数据时它会抛出异常。 如果我们想确保数据存在,我们应该使用 get() 方法。
简而言之,您应该了解两者之间的区别,并决定哪种方法最适合您的应用程序。
我在教程Difference between get and load method in Hibernate中发现了这种差异
【讨论】:
来自“Java Persistence with Hibernate”一书,第 405 页:
get() 和 load() 之间的一个区别是它们如何表示 找不到实例。 如果没有具有给定标识符的行 value 存在于数据库中,get() 返回 null。 load() 方法 抛出 ObjectNotFoundException。什么是你的选择 您喜欢的错误处理。
更重要的是,load() 方法可能 返回一个代理,一个占位符,不访问数据库。一种 这样做的结果是你可能会得到一个 ObjectNotFoundException 稍后,一旦您尝试访问返回的占位符并强制 它的初始化(这也称为延迟加载;我们讨论加载 后面章节中的优化。) load() 方法总是试图 返回一个代理,并且只返回一个初始化的对象实例,如果 它已经由当前的持久性上下文管理。在里面 前面显示的示例,根本没有发生数据库命中! get() 方法 另一方面,从不返回代理,它总是访问数据库。
您可能会问为什么这个选项很有用——毕竟,您检索的是 对象来访问它。获取持久化实例是很常见的 将其分配为对另一个实例的引用。例如,想象 您需要该项目仅用于一个目的:设置 与评论的关联:aComment.setForAuction(item)。如果这是 您计划对物品做的所有事情,代理都可以;没有 需要打数据库。换句话说,当评论被保存时, 您需要插入到 COMMENT 中的项目的外键值 桌子。 Item 的代理仅提供:标识符值 包裹在一个看起来像真的东西的占位符中。
【讨论】:
例如:如果您尝试加载 /get Empoyee 对象,其中 empid=20。但假设记录在 DB 中不可用。
Employee employee1 = session.load(Employee.class,20); //Step-1
system.out.println(employee1.getEmployeeId(); //Step-2 --o/p=20
system.out.println(employee1.getEmployeeName(); //Step-3 -->O/P:ObjectNotFoundException
如果您在步骤 1 中使用负载,那么此时休眠不会触发任何选择查询以从数据库中获取员工记录。此时休眠会提供一个虚拟对象(代理)。这个虚拟对象不包含任何东西。它是新员工(20)。您可以在步骤 2 中验证这一点 它将打印 20。但在第 3 步中,我们正在尝试查找员工信息。所以此时hibernate会触发一个sql查询来获取Empoyee objct。如果在 DB.throw ObjectNotFoundException 中没有找到。
Employee employee2 = session.get(Employee.class,20); //Step-4
for session.get() hibernate 触发一个 sql 查询以从 db 中获取数据。所以在我们的例子中 id=20 在数据库中不存在。所以它会返回null。
【讨论】:
当调用 Load 时,它返回一个代理对象。实际的选择查询仍未触发。当我们第一次使用任何映射属性时,实际查询会被触发。如果数据库中不存在行,它将引发异常。例如
Software sw = ( Software )session.load(Software.class, 12);
这里的 sw 是代理类型。并且尚未调用选择查询。 在 Eclipse 调试器中你可能会看到它像
sw Software$$EnhancerByCGLIB$$baf24ae0 (id=17)
CGLIB$BOUND true
CGLIB$CALLBACK_0 CGLIBLazyInitializer (id=23)
CGLIB$CALLBACK_1 null
CGLIB$CONSTRUCTED true
id null
prop1 null
softwareprop null
当我使用时
sw.getProp1()
选择查询被触发。现在代理现在知道所有映射属性的值。
当调用 get 时,选择查询会立即触发。返回的对象不是代理,而是实际类。例如
Software sw = ( Software )session.get(Software.class, 12);
这里的 sw 是软件本身的类型。如果行存在,则所有映射属性都将填充 DB 中的值。如果行不存在,则 sw 将为空。
sw Software (id=17)
id Integer (id=20)
prop1 "prodjlt1" (id=23)
softwareprop "softwrjlt1" (id=27)
如常说的,只有在您确定数据库中确实存在该记录时才使用加载。在这种情况下,使用代理是无害的,并且将有助于延迟数据库查询,直到实际需要映射属性。
【讨论】:
这些方法的语义解释并不能解释它们之间的实际区别。实用规则如下:
当你想加载一个对象时使用get()
当您需要在不发出额外 SQL 查询的情况下获取对对象的引用时使用load(),例如创建与另一个对象的关系:
public void savePost(long authorId, String text) {
Post p = new Post();
p.setText(text);
// No SELECT query here.
// Existence of Author is ensured by foreign key constraint on Post.
p.setAuthor(s.load(Author.class, authorId));
s.save(p);
}
【讨论】:
load() 返回一个Author 对象,其id 字段具有值,但每个非id 字段(如作者姓名、作者国家等)都是NULL。那是对的吗 ?此外,当您的事务尚未提交,并且您尝试访问空字段时,hibernate 将发出查询以仅获取并设置请求的字段?还是会获取并设置所有空字段?请告诉我。谢谢。
load() 返回的代理的空字段将触发数据库访问以获取所有字段(不仅是请求的字段),请参见 - stackoverflow.com/questions/8044963/…
load 会返回一个代理对象。
get 会返回一个实际的对象,如果找不到任何对象则返回 null。
【讨论】:
A:这在 hibernate 参考中有所解释。一个区别是性能,另一个区别是当没有找到该 ID 的 Object 时,load 会抛出一个不可恢复的异常。
更多详情here
【讨论】: