Hibernate 5.2以降、大量のデータをフェッチする場合は、stream()
ではなくscroll()
メソッドを使用できます。
ただし、scroll()
をScrollableResults
とともに使用すると、取得プロセスにフックし、オブジェクトを処理した後に永続コンテキストからオブジェクトを削除するか、オブジェクトをクリアすることでメモリを解放できます。セッション全体が時々。
私の質問:
stream()
メソッドを使用すると、舞台裏で何が起こりますか?hibernate.jdbc.fetch_size
をJPAプロパティでいくつかの数値(たとえば、1000)に変更した場合、これをスクロール可能な結果とどのように組み合わせるのでしょうか。次は私のために働きます:
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への接続を閉じることに注意してください。
Hibernate ORMユーザーガイド それを示す
内部的には、stream()はQuery#scrollのように動作し、基になる結果はScrollableResultsによってサポートされます。
_org.hibernate.query.internal.AbstractProducedQuery
_の ソースコード をチェックして、セッションを定期的にクリアするか、永続的なコンテキストからオブジェクトを削除する必要があることを確認できます。
コメントからわかるように、StatelessSession
はオプションではありません。あなたのケースを解決するきれいな方法はあなた自身のstream()
メソッドを実装することだと思います。それは元の方法と非常に似ている可能性があります。ScrollableResultsIterator
を、反復中に必要なこと(オブジェクトの削除またはセッションのクリア)を実行する独自のものに置き換えるだけです。