在Spring JPA Hibernate中了解延迟加载的事务会话 [英] Understanding transaction session with lazy loading in 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屋!