我与链接表中的附加列存在多对多关系。我已经将它配置为拥有方获取 child 渴望的方式(所以我没有得到 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。有点令人困惑,因为我看不出这会影响加载哪些数据的任何原因?

编辑:

关系定义的片段。这是一个多对多的链接表中的一列。

拥有方(例如化合物包含结构):
@OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.compound", 
    cascade = CascadeType.ALL, orphanRemoval = true) 
@OrderBy("pk.structure.id ASC") 
private List<CompoundComposition> composition = new ArrayList<>(); 

属于方:
@OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.structure", 
cascade = CascadeType.ALL) 
@OrderBy("pk.compound.id ASC") 
private List<CompoundComposition> occurence; 

@Embeddable ID 类中的多对一
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) 
public Compound getCompound() { 
    return compound; 
} 
 
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) 
public Structure getStructure() { 
    return structure; 
} 

编辑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:

所以我厌倦了基本的 DriverManagerDataSource 并且没有连接池。这个问题是完全一样的。对我来说,这看起来像是 Hibernate 中的一个问题。

请您参考如下方法:

这只是哇。我开始明白为什么有些人讨厌 ORM ......感觉就像我经常不得不花几个小时来解决一个奇怪的问题,而解决方案是一组非常具体的注释 + 一些代码来解决上述限制注释。

首先是为什么会发生这种情况(为什么用哪些注释表示,而不是在逻辑意义方面,这是这里的实际问题,因为使用常识是无用的。只有反复试验才有帮助)。在拥有方面,在@OneToMany 中,我有 orphanRemoval = true (我发现这是一致性所必需的。有人会认为数据库约束应该处理这个......这只是可能让你发疯的众多事情之一。)。似乎如果事务不是只读的,那么这个设置会导致一些数据被获取,即使它是惰性的,即这里:

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) 
public Structure getStructure() { 
    return structure; 
} 

在只读事务中,不会发生这种获取。我猜是因为如果您无法更改任何内容,您也不必删除孤儿,因此在只读 tx 中不需要此设置背后的逻辑所需的任何数据。

因此,显而易见的解决方案将与更改为 FetchType.EAGER 相关。错误的!如果这样做,您将无法使用 session.merge 更新拥有方(复合)。这将导致 StackOverFlowError。

真正的解决方案实际上已经提到了。只需保持配置不变,但在服务层中显式加载所需的关系:
@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 个元素。


评论关闭
IT干货网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!