其他分享
首页 > 其他分享> > 在Spring JPA Hibernate中了解延迟加载的事务会话

在Spring JPA Hibernate中了解延迟加载的事务会话

作者:互联网

我想对延迟加载和会话边界等做一些澄清.

我的代码结构如下

@Entity

class A {

....

  @OneToOne(fetch=LAZY)
  private B b;

  ..
}

@Entity
class B {

 private id;

 private name;    

}

@Transactional(SUPPORTS)
ADao {
  A findById(int id);  
}

@Transactional(SUPPORTS)
LayerDB {

    A getAForId(int i) {
      return adao.findById(i);
    }

}

//Note that there is no transactional attribute here
LayerB {

   public boolean doSomethingWithAandB(int aId) {
    A a = LayerDB.getAForId(aId);
    if(a.getB().getName().equals("HIGH"))
     return true;
    return false;
   }

}

//start transaction here
@Transaction(REQUIRED)
LayerC {

    LayerB layerb;

    private handleRequest(int id) {

       layerb.doSomethingWithAandB(id);

    }
}

现在,当我们尝试在方法中访问实体A中的B.

doSomethingWithAandB

尝试访问B时出现延迟初始化异常

即使该方法在LayerC中创建的事务中,仍然会出现以下异常

Exception : org.hibernate.LazyInitializationException: could not initialize proxy - no Session

但是在改变以下两种方法时:

@Transactional(SUPPORTS)
LayerDB {

   A getAForId(int i) {
      A a = adao.findById(i);
      a.getB().getName();
      return a;
    }

}

//Note that there is no transactional attribute here
LayerB {

   public boolean doSomethingWithAandB(int aId) {
     A a = LayerDB.getAForId(aId);
     if(a.getB().getName().equals("HIGH"))
     return true;
    return false;
  }

}

为什么不使用在LayerC中创建的事务/会话?

即使我们在DBLayer上有SUPPORTS,它是否会创建一个单独的“会话”.

任何正确理解的指针都会对我有所帮助.

谢谢.

解决方法:

使用延迟加载时,当您请求类型A的对象a时,您将获得类型为A的对象a.a.getB()但是,不会是类型B,而是a.getB()是B的代理,可以稍后解决(这是延迟加载部分),但仅限于生存的持久化上下文.

你的第二个实现就是这样:当你仍然在@Transaction时,它通过调用a.getB().getName()来解析B. Hibernate现在可以向数据库发出第二个请求以获取B,现在a.getB()实际上是B类并保持这种状态,因此您可以在持久化上下文之外使用它.

你的第一个实现跳过了.从数据库中获取A,@ Transaction块结束,然后调用a.getB().getName(),但现在持久化上下文消失了,无法从数据库中获取a.getB(),并且异常被扔了.

标签:exception,spring,jpa,lazy-loading,spring-transactions
来源: https://codeday.me/bug/20190713/1450970.html