2012-10-09 7 views
6

リンクテーブルに追加の列と多対多の関係があります。私は、所有側が子どもたちを熱心に取り出すように(つまり私はLazyInitializationExceptionを得ていない)、反対方向には怠け者であるように設定しました。これは機能します。@Transactional(readOnly = true)はLazyInitializationExceptionにつながります。

だけ@Transactional DAOとサービスクラスのクラスレベルのがあった前に、私は今、(微調整をするために、トランザクションに望んでいた私はreadOnly = trueにメソッドgetByIdを設定します。

@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)を削除した場合、私は、なぜ番目のいずれかの理由が表示されないよう、私は混乱の春+休止状態の種類を使用!?。どのデータが読み込まれるかに影響するでしょうか?


EDIT:関係定義の

スニペット。これはリンクテーブルの列を持つ多対多です。

所有側(例えば化合物は、構造が含まれています):

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

EDIT 2:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.compound", 
    cascade = CascadeType.ALL, orphanRemoval = true) 
@OrderBy("pk.structure.id ASC") 
private List<CompoundComposition> composition = new ArrayList<>(); 

は左右に属し:

St ACKトレース

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] 

EDIT 3:

ログインが読み取り専用と非常に異なっており、一部の関係は例えば、ロードされた欠落しています。

はまた、私のコメントを参照してください。いくつかの選択肢がログにありません。

EDIT 4:基本的なDriverManagerDataSourceなし接続プールと

だから私は疲れました。問題はまったく同じです。私にとっては、Hibernateの問題のように見えます。遅延ロードがトランザクション内で起こるように

+0

クラスレベルのトランザクション定義とは何ですか? –

+0

@Transactionalだけです。 –

+0

モデルクラスのスニペットを投稿できますか? DAOクラスのトップに '@ Transactional'アノテーションがありますか? – sbzoom

答えて

3

これはちょうどうわーです。私は何人かの人々がORMを嫌う理由を理解し始めています...ちょっと変わった問題を解決するために何時間も費やさなければならないと感じ、ソリューションは非常に特殊な注釈セット+注釈。

なぜこのようなことが起こるのか(なぜ、アノテーションが意味を持つのか、論理的な意味で使われているのか、常識を使って実際に問題になっているのは意味がないからです。所有側では、@OneToManyではorphanRemoval = true(一貫性のために必要なことを知っています。データベース制約はそれを処理する必要があると思うでしょう...あなたを狂わせる多くの事の一つです)。読取り専用トランザクションでは

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

、このフェッチが発生しません:トランザクションが読み取り専用でない場合は、この設定がそうであってもフェッチされるデータの一部に、すなわちここでは、その怠惰をリードしているようです。あなたが何かを変更できない場合は、孤児を削除する必要がないため、この設定の背後にあるロジックに必要なすべてのデータが読み取り専用のtxでは必要ないため、私は推測します。

したがって、FetchType.EAGERに変更するには上記の関係になるはずです。違う!これを行うと、session.mergeを使用して所有側(Compound)を更新することができなくなります。これにより、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つの要素しか含まれていないという運が良かったです。

+1

あなたの最初の2つの段落は、私がHibernate/JPA/ORMと一緒に過ごした6 - – millhouse

0

おそらくあなたは、getById()メソッドの本体に

value.getComposition().get(i).getStructure(); 

を置くことができます。この場合、iをループする必要がありますが、これは不便かもしれません。

関連する問題