【问题标题】:Hibernate - Avoiding LazyInitializationException - Detach Object From Proxy and SessionHibernate - 避免 LazyInitializationException - 从代理和会话中分离对象
【发布时间】:2011-03-31 03:27:45
【问题描述】:
MyObject myObject = repositoryHibernateImpl.getMyObjectFromDatabase();
//transaction is finished, and no, there is not an option to reopen it
ThirdPartyUtility.doStuffWithMyObjectType( myObject );

此时您已经定义了什么是惰性加载和急切加载,第三方实用程序将尝试调用您的“myObject”实例上的所有方法,这很好,因为您不想返回任何内容对于延迟加载的属性,不幸的是它不会返回 null,它会抛出一个 LazyInitializationException

发生这种情况是因为您实际上是在 Hibernate 的对象代理上调用该方法,并且它知道它没有获取该数据并引发异常。

是否甚至可以使用 null 值获取底层对象,以便 getter 只返回 null 并且不引发异常?基本上是分离对象,这样 Hibernate 就不再知道它了。延迟加载的对象的访问器必须返回 null,它不能返回实际值,我们希望能够将实体转换为 POJO,而不必创建一个看起来像实体的对象并且必须重新映射所有价值观。

【问题讨论】:

    标签: java hibernate lazy-loading


    【解决方案1】:

    假设你有一个字段,你可以在 getter 中:

    MyField getMyField() {
        if (Hibernate.isInitialized(myField)) {
            return myField;
        }
        return null;
    }
    

    来自 org.hibernate.Hibernate 的 javadoc:

    公共静态布尔值 isInitialized(Object proxy): 检查是否 代理或持久集合是 初始化。

    【讨论】:

    • 这是一个非常有趣的解决方案,它显然有一个缺点是实体变得与休眠紧密耦合,但除非有一个没有耦合的答案,否则我认为这是赢家
    【解决方案2】:

    如果您不想将您的域与 Hibernate 耦合,另一种可能性是让您的 DAO 从内部 getMyObjectFromDatabase() 实例化您自己的实体实例,并使用来自 Hibernate 代理的适当字段填充该实例。我已经这样做了,而且效果很好。

    显然这是更多的代码,但如果这是你想要的,你可以保证你的实体的“纯”实例(包含未初始化的空值)。

    【讨论】:

      【解决方案3】:

      检查我的解决方案。

      小例子:

      我不是从对象加载属性,而是从控制器加载。
      代码:

      {..}
      
      MyProp prop = employeeController.getMyProp(employee);
      
      {..}
      

      这会通过存储库对象初始化属性并返回它。
      EmployeeController.java:

      public Set<MyProp> getMyProp(Employee employee) {
      
          if (this.employeeRepository.InitMyProp(employee)){
      
              return employee.getMyProp();
          }
      
          return null;
      }
      

      Repository 获取/打开会话,重新加载员工对象!并初始化延迟加载字段
      EmployeeRepository.java:

      public boolean InitMyProp(Employee employee) {
      
          if (Hibernate.isInitialized(employee.getMyProp())){
              return true;
          }
      
          try {
              Session session = getSession();
      
              session.refresh(employee);
      
              Hibernate.initialize(employee.getMyProp());
      
          } catch (Exception ex) {
              return false;
          }
      
          return true;
      }
      
      private Session getSession(){
      
          if (session == null || !session.isConnected() || !session.isOpen()){
              session = HibernateUtil.getSessionFactory().getCurrentSession();
          }
          if (!session.getTransaction().isActive()) {
              session.beginTransaction();
          }
          return session;
      }
      

      我的解决方案中有一个包含数千条记录的 TableView 和另外 2 个 TableView,其中包含第一个 TableView 中所选记录的详细信息。
      希望有帮助。

      【讨论】:

      • 为什么这样可以解决问题?您能否通过编辑您的帖子并提供有关您的代码的更多信息来提高您的回答质量?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-27
      • 1970-01-01
      • 2019-12-11
      • 2011-09-16
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      相关资源
      最近更新 更多