3

私はJavaの休止状態5.2.10を使用することを学んでいます。オンラインでいくつかのチュートリアルを開始しましたが、次の質問に直面しました。

バッチ処理を使用する場合、私が見たすべてのチュートリアルでは、最初hibernate.jdbc.batch_sizeに構成ファイルに を設定しました。その後、コードは次のようになります。

Session session = SessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<1000000; i++ ) 
{
    Student student = new Student(.....);
    session.save(employee);
    if( i % 50 == 0 ) // Same as the JDBC batch size
    { 
        //flush a batch of inserts and release memory:
        session.flush();
        session.clear();
    }
}
tx.commit();
session.close();

なぜ手動でflush()行う必要があるのですか? これは、構成ファイルにclear()既に設定されているため、休止状態によって自動的に行われるべきものではありませんか?hibernate.jdbc.batch_size

私にとっては、操作を手動でバッチ処理しているように見えますが、なぜhibernate.jdbc.batch_sizethen の値を設定する必要があるのでしょうか?

4

3 に答える 3

5

構成で JDBC batch_size 値を指定する使用と、永続コンテキストのフラッシュ/クリアを手動で制御する使用は、2 つの独立した戦略であり、非常に異なる目的を果たします。

flush()とペアで使用する主な目的はclear()、生徒の記録を保存するときに PersistenceContext によって使用される Java アプリケーション側のメモリ消費を最小限に抑えることです。例が示すようにステートフルを使用している場合Session、Hibernate はエンティティの添付/管理されたコピーをメモリ内に維持することを覚えておくことが重要です。したがって、メモリ不足を避けるために、定期的にこれをクリアしてデータベースにフラッシュすることが重要です。またはパフォーマンスに影響を与えます。

JDBC の batch_size 設定自体は、パフォーマンスを向上させるために実際のドライバーがステートメントをデータベースにフラッシュする頻度に影響します。少し変更した例を見てみましょう。

Session session = sessionFactory.openSession();
try {
  session.getTransaction().begin();
  for ( int i = 0; i < 10000; ++i ) {
    Student student = new Student();
    ...        
    session.save( student );
  }
  session.getTransaction().commit();
}
catch( Throwable t ) {
  if ( session.getTransaction().getStatus() == TransactionStatus.ACTIVE ) {
    session.getTransaction().rollback();
  }
  throw t;
}
finally {
  session.close();
}

ご覧のとおり、ここではflush()orを使用していませんclear()

ここで何が起こるかというと、Hibernate はコミット時にフラッシュを実行するため、ドライバーはデータベースに個別にではなく、batch_size の数の挿入を一括で送信します。したがって、10,000 個のネットワーク パケットが送信されるのではなく、batch_size が 250 の場合、40 個のパケットしか送信されません。

ここで重要なのは、やなどの ID ベースの識別子を使用するなど、バッチ処理を無効にする要因があることです。なんで?IDENTITYAUTO_INCREMENT

これは、Hibernate がエンティティを PersistenceContext に格納するには、エンティティの ID を知る必要があり、IDENTITYベースの識別子生成を使用するときにその値を取得する唯一の方法は、各挿入操作の後に実際にデータベースに値をクエリすることであるためです。したがって、挿入をバッチ処理することはできません。

これこそまさに、一括挿入操作を行っている人が、選択した識別子生成戦略が与える影響を認識していないため、パフォーマンスの低下を観察することが多い理由です。

バッチの読み込みを最適化する場合は、代わりに、キャッシュされたシーケンス ジェネレーターまたは手動でアプリケーションに割り当てられた識別子を使用することをお勧めします。

とを使用した例に戻るflush()clear()、同じ問題が識別子生成戦略にも当てはまります。これらの操作をデータベースに一括/バッチで送信する場合は、 に使用している識別子戦略に注意してくださいStudent

于 2017-07-10T17:01:58.513 に答える