web-dev-qa-db-ja.com

Hibernate 5.2を使用したスト​​リームとしての結果のクエリ

Hibernate 5.2以降、大量のデータをフェッチする場合は、stream()ではなくscroll()メソッドを使用できます。

ただし、scroll()ScrollableResultsとともに使用すると、取得プロセスにフックし、オブジェクトを処理した後に永続コンテキストからオブジェクトを削除するか、オブジェクトをクリアすることでメモリを解放できます。セッション全体が時々。

私の質問:

  1. ここで、stream()メソッドを使用すると、舞台裏で何が起こりますか?
  2. 永続的なコンテキストからオブジェクトを削除することは可能ですか?
  3. セッションは定期的にクリアされますか?
  4. どのようにして最適なメモリ消費が達成されますか?
  5. 使用可能です。 StatelessSession?
  6. また、hibernate.jdbc.fetch_sizeをJPAプロパティでいくつかの数値(たとえば、1000)に変更した場合、これをスクロール可能な結果とどのように組み合わせるのでしょうか。
17
kmandalas

次は私のために働きます:

DataSourceConfig.Java

@Bean
public LocalSessionFactoryBean sessionFactory() {
    // Link your data source to your session factory
    ...
}

@Bean("hibernateTxManager")
public HibernateTransactionManager hibernateTxManager(@Qualifier("sessionFactory") SessionFactory sessionFactory) {
    // Link your session factory to your transaction manager
    ...
}

MyServiceImpl.Java

@Service
@Transactional(propagation = Propagation.REQUIRES_NEW, transactionManager = "hibernateTxManager", readOnly = true)
public class MyServiceImpl implements MyService {

    @Autowired
    private MyRepo myRepo;
    ...
    Stream<MyEntity> stream = myRepo.getStream();
    // Do your streaming and CLOSE the Steam afterwards
    ...

MyRepoImpl.Java

@Repository
@Transactional(propagation = Propagation.MANDATORY, transactionManager = "hibernateTxManager", readOnly = true)
public class MyRepoImpl implements MyRepo {

    @Autowired
    private SessionFactory sessionFactory;

    @Autowired
    private MyDataSource myDataSource;

    public Stream<MyEntity> getStream() {

        return sessionFactory.openStatelessSession(DataSourceUtils.getConnection(myDataSource))
            .createNativeQuery("my_query", MyEntity.class)
            .setReadOnly(true)
            .setFetchSize(1000)
            .stream();
    }
    ...

ストリーミングするときは、オブジェクトの具体化の時点でメモリに注意するだけで十分です。これが、メモリ内の問題の影響を受けやすい操作の唯一の部分です。私の場合、一度に1000オブジェクトずつストリームをチャンク化し、gsonを使用してそれらをシリアル化し、すぐにJMSブローカーに送信します。あとはガベージコレクターが行います。

Springのトランザクション境界認識は、明示的に指示される必要なく、最後にdBへの接続を閉じることに注意してください。

9
wild_nothing

Hibernate ORMユーザーガイド それを示す

内部的には、stream()はQuery#scrollのように動作し、基になる結果はScrollableResultsによってサポートされます。

_org.hibernate.query.internal.AbstractProducedQuery_の ソースコード をチェックして、セッションを定期的にクリアするか、永続的なコンテキストからオブジェクトを削除する必要があることを確認できます。

コメントからわかるように、StatelessSessionはオプションではありません。あなたのケースを解決するきれいな方法はあなた自身のstream()メソッドを実装することだと思います。それは元の方法と非常に似ている可能性があります。ScrollableResultsIteratorを、反復中に必要なこと(オブジェクトの削除またはセッションのクリア)を実行する独自のものに置き換えるだけです。

5
VitalyZ