我想澄清有关延迟加载和 session 边界等问题。

我的代码结构如下

@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中创建的事务/ session ?

即使我们在DBLayer上有支持,它是否仍在创建单独的“ session ”。

任何适当理解的指示都会对我有很大帮助。

谢谢你。

最佳答案

在延迟加载中,当您请求类型为A的对象a时,您将得到类型为A的对象a。但是,a.getB()不会是类型B,而是a.getB()是B的代理,以后可以解析(加载部分),但仅在其中存在的持久性上下文中。

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

您的第一个实现跳过了这一点。从数据库中获取A,@Transactional块结束,然后调用a.getB().getName(),但是现在持久性上下文消失了,无法从数据库中获取a.getB(),并引发了异常。

10-06 03:38