在Spring JPA Hibernate中了解延迟加载的事务会话 [英] Understanding transaction session with lazy loading in Spring JPA Hibernate

查看:135
本文介绍了在Spring JPA Hibernate中了解延迟加载的事务会话的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我的代码结构如下

  @Entity 

class A {

....

@OneToOne(fetch = LAZY)
private B b;

..
}

@Entity
class B {

private id;

私人名称

}

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

@Transactional(SUPPORTS)
LayerDB {

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

}

//注意这里没有事务属性
LayerB {

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

}

//开始事务
@Transaction(REQUIRED)
LayerC {

LayerB layerb;

private handleRequest(int id){

layerb.doSomethingWithAandB(id);

}
}

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

  doSomethingWithAandB 

尝试访问B时,会收到一个懒惰的初始化异常。



即使该方法在LayerC中创建的事务中,仍然我得到以下异常

 异常:org.hibernate.LazyInitializationException:无法初始化代理 - 无会话

但是,将以下两种方法更改为:

  @Transactional(SUPPORTS)
LayerDB {

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

}

//注意这里没有事务属性
LayerB {

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

}

为什么不使用交易/ session在LayerC中创建?



即使我们在DBLayer上有SUPPORTS,是否创建了一个单独的会话。



/ p>



解决方案

使用延迟加载,当您请求A类型的对象时,您将获得一个类型为A的对象。 a.getB()然而,不会是类型B,而是 a.getB()是B的代理,可以稍后解决(这是懒惰加载部分),但只有在



您的第二个实现只是这样:它通过调用 a.getB()来解析B getName( ),而您仍然在 @Transaction 中。 Hibernate现在可以向数据库发出第二个请求以获取B,现在 a.getB()真的是类型B,并保持这种方式,所以你可以在外面使用它持久性上下文。



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


I would like to get some clarification regarding lazy loading and session boundaries etc.

My code structure is as follows

@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);

    }
}

Now when we try to access B in entity A within the method

doSomethingWithAandB

Am getting a lazy initialization exception when trying to access B.

Even though the method is within the transaction created in LayerC, still i get the following exception

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

But on changing the following two methods as :

@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;
  }

}

Why is it not using the transaction / session created in LayerC ?

Even though we have SUPPORTS on the DBLayer, is it creating a separate 'session'.

Any pointers for proper understand would help me a great deal.

Thank you.

解决方案

With lazy loading, when you request an object a of type A, you get an object a of type A. a.getB() however, will not be of type B, instead a.getB() is a proxy for B that can be resolved later on (that's the lazy loading part), but only in the persistence context in which a lives in.

Your second implementation does just that: it resolves B by calling a.getB().getName() while you are still in the @Transaction. Hibernate can now make a second request to the database to fetch B, and now a.getB() is really of type B and stays that way, so you can use it outside the persistence context.

Your first implementation skips that. A is fetched from the database, the @Transactional block ends, then you call a.getB().getName(), but now the persistence context is gone, a.getB() can not be fetched from the database, and an exception is thrown.

这篇关于在Spring JPA Hibernate中了解延迟加载的事务会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆