2017-03-03 13 views
6

トランザクションスコープ内でコレクションにアクセスするときに遅延ロードされたコレクションをフェッチする必要があります。たとえば、コレクションを取得したい場合はfoo.getBars.size()と呼ぶことができます。 ....プロキシ初期化できませんでした -Spring Data JPA - @Transactionalなしでフェッチされたレイジーロードされたコレクション

しかしいいえセッションを:アクティブなトランザクションが存在しない場合は、遅延したバーのコレクションを初期化に失敗しました

のようなエラーメッセージと例外が発生しなければなりません最近のアプリケーションでは動作が違うことに気付きました。私はSpring Boot 1.5.1を "data-jpa"スターターと共に使用しています。私は過去にSpring Bootを使用しましたが、data-jpaスターターは私にとって新しいものです。

以下のケースを考慮してください。私は、怠惰に読み込まれたManyToManyコレクションを持っています。

@SuppressWarnings("serial") 
@Entity 
@Table(name = "foo") 
public class Foo implements java.io.Serializable { 
    .... 
    private Set<Bar> bars = new HashSet<Bar>(0); 
    .... 

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
    @JoinTable(name = "foo_bar_map", 
     joinColumns = {@JoinColumn(name = "foo_id", nullable = false, updatable = false)}, 
     inverseJoinColumns = {@JoinColumn(name = "bar_id", nullable = false, updatable = false)}) 
    public Set<Bar> getBars() { 
     return this.bars; 
    } 

    public void setBar(Set<Bar> bars) { 
     this.bars = bars; 
    } 

マイサービスメソッドがトランザクションとしてマークされていないが、私は

@Service 
public class FooServiceImpl implements FooService { 

    @Autowired 
    private FooRepository fooRepo; 


    @Override 
    public FooDTO findById(int fooId) { 
     Foo foo = fooRepo.findOne(fooId); 
     // The FooDTO constructor will access foo.getBars() 
     return new FooDTO(foo); 
    } 

そして、私の期待と過去に

public FooDTO(Foo foo) { 
    ... 
    for (Bar bar : foo.getBars()) { 
     this.bars.add(bar); 
    } 
} 

反しFooDTOコンストラクタのコンテキストのための遅延ロードされたコレクションにアクセスしていますこのコードは正常に実行され、コレクションをフェッチします。さらに、私がサービスメソッドにブレークポイントを投げた場合、コードをステップ実行して、fooRepoを呼び出した後でバーをフェッチするSQLログをログで見ることができます。 fooRepoへの私の呼び出しの後、私はトランザクションが閉じられると予想します。

ここには何が起こっていますか?

+0

サービスを呼び出すのは誰ですか?私の推測では、呼び出し元はトランザクションです。 –

+0

@JBNizetこのメソッドは、トランザクションとしてマークされていないコントローラによって呼び出されます。 –

+1

Springブートは、デフォルトでOpenEntityManagerInViewwInterceptorを使用しているようです:https://github.com/spring-projects/spring-boot/blob//boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java#L203を実行します。 http://docs.spring.io/spring-boot/docs/1.4.2.RELEASE/reference/htmlsingle/#common-application-properties(OpenEntityManagerInViewを検索してください) –

答えて

11

デフォルトでは、SpringブートはOpenEntityManagerInViewインターセプタを使用します。プロパティーspring.jpa.open-in-viewをfalseに設定することでオフにすることができます。

この(およびその他の)JPAプロパティについては、the documentationを参照してください。

+0

外では、findById、それはもう動作しませんか? –

1

ロギングをオンにして、トランザクションが開かれているかどうかを確認できます。

org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction 

または

org.hibernate.engine.transaction.internal.jta.JtaTransaction 

また、あなたはブレークポイントを設定し、トランザクションが開いているかどうかを確認するために、この静的メソッドを使用することができます。

org.springframework.transaction.support.TransactionSynchronizationManager.isActualTransactionActive() 
関連する問題