【问题标题】:What's the advantage of load() vs get() in Hibernate?Hibernate 中 load() 与 get() 的优势是什么?
【发布时间】:2011-07-19 05:37:46
【问题描述】:

谁能告诉我在 Hibernate 中 load() 与 get() 的优势是什么?

【问题讨论】:

    标签: java hibernate


    【解决方案1】:
    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.

    source

    代理意味着,hibernate 会在内存中准备一些具有给定标识符值的假对象,而不会访问数据库。

    例如:
    如果我们打电话给session.load(Student.class,new Integer(107));

    hibernate 会在内存中创建一个 id 为 107 的假 Student 对象 [row],但 Student 类的剩余属性甚至不会被初始化。

    Source

    【讨论】:

      【解决方案2】:

      Get() 通过从数据库或休眠缓存中获取对象来返回对象,而 load() 仅返回可能实际不存在的对象的引用,它仅在您访问其他属性时才从数据库或缓存中加载数据对象。

      使用 load(),我们可以打印 id,但是一旦我们尝试访问其他字段,它就会触发数据库查询并在没有找到具有给定标识符的记录时抛出 org.hibernate.ObjectNotFoundException。它是休眠特定的运行时异常,因此我们不需要显式捕获它。

      【讨论】:

        【解决方案3】:

        session.load(): 它将始终返回具有给定标识值的代理对象,即使该标识值在数据库中不存在。但是,当您尝试通过从数据库中检索代理的属性来初始化代理时,它将使用 select 语句访问数据库。如果没有找到行,则会抛出 ObjectNotFoundException。

        session.get(): 如果在数据库中找不到标识值,它将始终返回 null 。

        【讨论】:

          【解决方案4】:

          性能问题也是get和load方法的主要区别。

          get() 方法一执行就获取数据,而 load() 方法返回一个代理对象,并且只在需要对象属性时获取数据。 这样 load() 方法获得了更好的性能,因为它支持延迟加载。 只有当我们知道数据存在时才应该使用 load() 方法,因为当找不到数据时它会抛出异常。 如果我们想确保数据存在,我们应该使用 get() 方法。

          简而言之,您应该了解两者之间的区别,并决定哪种方法最适合您的应用程序。

          我在教程Difference between get and load method in Hibernate中发现了这种差异

          【讨论】:

            【解决方案5】:

            来自“Java Persistence with Hibernate”一书,第 405 页:

            get() 和 load() 之间的一个区别是它们如何表示 找不到实例。 如果没有具有给定标识符的行 value 存在于数据库中,get() 返回 null。 load() 方法 抛出 ObjectNotFoundException。什么是你的选择 您喜欢的错误处理。

            更重要的是,load() 方法可能 返回一个代理,一个占位符,不访问数据库。一种 这样做的结果是你可能会得到一个 ObjectNotFoundException 稍后,一旦您尝试访问返回的占位符并强制 它的初始化(这也称为延迟加载;我们讨论加载 后面章节中的优化。) load() 方法总是试图 返回一个代理,并且只返回一个初始化的对象实例,如果 它已经由当前的持久性上下文管理。在里面 前面显示的示例,根本没有发生数据库命中! get() 方法 另一方面,从不返回代理,它总是访问数据库。

            您可能会问为什么这个选项很有用——毕竟,您检索的是 对象来访问它。获取持久化实例是很常见的 将其分配为对另一个实例的引用。例如,想象 您需要该项目仅用于一个目的:设置 与评论的关联:aComment.setForAuction(item)。如果这是 您计划对物品做的所有事情,代理都可以;没有 需要打数据库。换句话说,当评论被保存时, 您需要插入到 COMMENT 中的项目的外键值 桌子。 Item 的代理仅提供:标识符值 包裹在一个看起来像真的东西的占位符中。

            【讨论】:

              【解决方案6】:
              • 要加载对象时使用 get()
              • 当您需要获取对对象的引用时,请使用 load() 发出额外的 SQL 查询,例如,创建与 另一个对象:

              例如:如果您尝试加载 /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。

              【讨论】:

                【解决方案7】:

                当调用 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)    
                

                如常说的,只有在您确定数据库中确实存在该记录时才使用加载。在这种情况下,使用代理是无害的,并且将有助于延迟数据库查询,直到实际需要映射属性。

                【讨论】:

                  【解决方案8】:

                  这些方法的语义解释并不能解释它们之间的实际区别。实用规则如下:

                  • 当你想加载一个对象时使用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 将发出查询以仅获取并设置请求的字段?还是会获取并设置所有空字段?请告诉我。谢谢。
                  • @BoratSagdiyev 访问由load() 返回的代理的空字段将触发数据库访问以获取所有字段(不仅是请求的字段),请参见 - stackoverflow.com/questions/8044963/…
                  • 正是我想要的答案!
                  【解决方案9】:

                  load 会返回一个代理对象。

                  get 会返回一个实际的对象,如果找不到任何对象则返回 null。

                  【讨论】:

                    【解决方案10】:

                    A:这在 hibernate 参考中有所解释。一个区别是性能,另一个区别是当没有找到该 ID 的 Object 时,load 会抛出一个不可恢复的异常。

                    更多详情here

                    【讨论】:

                      猜你喜欢
                      • 2011-03-25
                      • 2011-02-07
                      • 1970-01-01
                      • 2014-06-03
                      • 2016-07-03
                      • 2014-08-03
                      • 2015-03-05
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多