Spring @事务性(readOnly=true)导致LazyInitializationException
我与链接表中的一个附加列有多对多关系。我将其配置为拥有方获取渴望的子对象(因此我没有得到Spring @事务性(readOnly=true)导致LazyInitializationException,spring,hibernate,transactions,Spring,Hibernate,Transactions,我与链接表中的一个附加列有多对多关系。我将其配置为拥有方获取渴望的子对象(因此我没有得到LazyInitializationException),相反,它是懒惰的。这很有效 现在我想对事务进行微调(在DAO和服务类的类级别上出现@Transactional之前)。我将方法getById设置为readOnly=true: @Transactional(readOnly = true) public Compound getById(Long id) { return compoundDA
LazyInitializationException
),相反,它是懒惰的。这很有效
现在我想对事务进行微调(在DAO和服务类的类级别上出现@Transactional
之前)。我将方法getById
设置为readOnly=true
:
@Transactional(readOnly = true)
public Compound getById(Long id) {
return compoundDAO.getById(id);
}
在这个更改之后,我在下面的代码段中得到了一个LazyInitializationException
:
Compound compound = compoundService.getById(6L);
Structure structure = compound.getComposition().get(0).getStructure();
System.out.println("StructureId: "+ structure.getId()); // LazyInitializationException
如果我删除(readOnly=true)
这就行了!有人能解释这个行为吗?我使用Spring+Hibernate。有点让人困惑,因为我看不出这会影响加载哪些数据的任何原因
编辑: 关系定义的片段。这是一个多对多的链接表,其中包含一列 拥有方(如化合物包含结构): 编辑2: 堆栈跟踪
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165) ~[hibernate-core-4.1.7.Final.jar:4.1.7.Final]
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:272) ~[hibernate-core-4.1.7.Final.jar:4.1.7.Final]
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185) ~[hibernate-core-4.1.7.Final.jar:4.1.7.Final]
at org.bitbucket.myName.myApp.entity.Structure_$$_javassist_0.getId(Structure_$$_javassist_0.java) ~[classes/:na]
at org.bitbucket.myName.myApp.App.main(App.java:31) ~[classes/:na]
编辑3:
另见我的评论:
日志与readOnly非常不同,它缺少加载关系的部分,例如,日志中缺少一些选择
编辑4:
所以我厌倦了使用基本的DriverManager数据源,而没有连接池。问题完全一样。对我来说,这就像是Hibernate中的问题。也许你可以
value.getComposition().get(i).getStructure();
在
getById()的主体中
方法,因此延迟加载发生在事务中。我意识到在这种情况下,您必须循环I
,这可能会很不方便。这只是一个惊喜。我开始理解为什么有些人讨厌ORM…只是感觉我经常不得不花费数小时来解决一个奇怪的问题,而解决方案是一个非常复杂的问题cific注释集+一些代码,以克服上述注释的限制
首先是为什么会发生这种情况(为什么注释的意思是什么,但不是在逻辑意义上,这是这里的实际问题,因为使用常识是无用的。只有尝试和错误才有帮助)。在拥有方,在@OneToMany中,我有一个=true(我发现这是一致性所必需的。有人会认为数据库约束应该处理这一点……这只是让你发疯的众多因素之一。)似乎,如果事务不是只读的,那么此设置会导致某些数据被提取,即使它是惰性的,即:
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Structure getStructure() {
return structure;
}
在只读事务中,这种抓取不会发生。我猜这是因为如果您不能更改任何内容,您也不必删除孤立项,因此在只读事务中不需要此设置背后的逻辑所需的任何数据
因此,显而易见的解决方案是在上面的关系中更改为FetchType.EAGER.Error!如果这样做,您将无法使用session.merge更新拥有方(化合物)。这将导致StackOverflower错误
实际上已经提到了真正的解决方案。只需保持配置不变,但在服务层中显式加载所需的关系:
@Transactional(readOnly = true)
@Override
public Compound getById(Long id) {
Compound compound = compoundDAO.getById(id);
for (CompoundComposition composition : compound.getComposition()){
Hibernate.initialize(composition.getStructure());
}
return compound;
}
我承认我倾向于落入过早优化的陷阱。这看起来效率不高,而且似乎打破了SQL的工作原理。但我很幸运,在大多数情况下,CompoundComposition只包含1或2个元素。两件事:-
延迟获取在集合接口上工作。因为
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Structure getStructure() {
return structure;
}
…这不是一个收集接口(如列表
),它将以急切获取模式获取
将服务方法设置为事务性。从dao层获取后,您的结构似乎会以从不刷新模式分离。我想这就是ORM的基本问题。类级别事务定义是什么?您可以发布模型类的片段吗?并且,您是否仍然在DAO类之首?尝试了不同的版本,从在服务类中使用@Transactional only到在所有DAO类中使用@Transactional only,效果相同。添加只读会导致LazyInitializationException。我不相信您的异常是事务模式的原因,当您调用ws-Lazy初始化异常?stacktrace也会有帮助。前两段总结了我在Hibernate/JPA/ORMs上花了6年左右的时间。
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Structure getStructure() {
return structure;
}
@Transactional(readOnly = true)
@Override
public Compound getById(Long id) {
Compound compound = compoundDAO.getById(id);
for (CompoundComposition composition : compound.getComposition()){
Hibernate.initialize(composition.getStructure());
}
return compound;
}
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public Structure getStructure() {
return structure;
}