この記事では、冬眠バッチ操作の方法について説明します。次のように、参照のために共有してください。
冬眠バッチ処理
Hibernateは、オブジェクト指向の方法で完全にデータベースを操作します。永続的なオブジェクトがプログラム内のオブジェクト指向の方法で動作すると、データベースの操作に自動的に変換されます。たとえば、sessionのdelete()メソッドを呼び出して永続的なオブジェクトを削除する場合、hibernateは対応するデータレコードの削除を担当します。永続オブジェクトの設定方法を実行すると、Hibernateは対応する更新メソッドに自動的に変換され、データベースの対応するレコードを変更します。
問題は、100,000のレコードを同時に更新する必要があるかどうか、100,000のレコードを1つずつロードする必要がありますか、次にセットメソッドを順番に呼び出す必要がありますか?これは面倒であるだけでなく、データアクセスのパフォーマンスも非常に悪いです。このバッチ処理シナリオでは、Hibernateはバッチ処理ソリューションを提供します。以下は、バッチ挿入、バッチアップデート、バッチ削除の3つの側面からこのバッチ処理の状況に直面する方法を紹介します。
1バッチ挿入
データベースに100,000のレコードを挿入する必要がある場合、冬眠は通常以下を使用できます。
セッションセッション= sessionfactory.opensession();トランザクションtx = session.begintransaction(); session.save(customer);} tx.commit(); session.close();
しかし、このプログラムが実行されると、ある時点で常に失敗し、OutFmemoryExceptionがスローされます。これは、Hibernateのセッションが必要なレベル1キャッシュを保持しており、すべてのユーザーインスタンスがセッションレベルのキャッシュ領域でキャッシュされるためです。
この問題を解決するために、非常に簡単なアイデアがあります。セッションレベルで常にキャッシュするのではなく、セッションによってキャッシュされたデータを定期的にデータベースに更新します。アキュムレータの設計を検討することができます。アキュムレータは、保存されたユーザーインスタンスごとに1増加します。セッションキャッシュ内のデータをアキュムレータ値に基づいてデータベースに流す必要があるかどうかを判断します。
これは、100,000のユーザーインスタンスを追加するコードのスニペットです。
private void testuser()スロー例外{//セッションセッション= hibernateutil.currentsession(); //トランザクショントランザクションを開始するtx = session.begintransaction(); // 100,000回ループして、(int i = 0; i <1000000; i ++){//ユーザーインスタンスユーザーu1 = new user();を作成する100,000レコードを挿入します。 u1.setname( "xxxxx" + i); u1.setage(i); u1.setnationality( "China"); //ユーザーインスタンスsession.save(u1); //アキュムレータが20の倍数である場合は、セッション内のデータをデータベースにフラッシュし、セッションキャッシュをクリアします(i%20 == 0){session.flush(); session.clear(); tx.commit(); tx = session.begintransaction(); }} // Transaction tx.commit()をコミットします。 //トランザクションhibernateutil.closessession();}を閉じる上記のコードでは、i%20 == 0の場合、セッションのキャッシュデータがデータベースに手動で書き込まれ、トランザクションが手動で送信されます。トランザクションが送信されていない場合、データはトランザクションオフィスで引き続きキャッシュされます - データベースに入力していないため、メモリオーバーフローの例外も引き起こします。
これはセッションレベルのキャッシュの処理であり、SessionFactoryのセカンダリキャッシュも次の構成を介してオフにする必要があります。
hibernate.cache.use_second_level_cache false
注:セッションレベルのキャッシュを手動でクリアすることに加えて、SessionFactoryレベルのセカンダリキャッシュをオフにすることをお勧めします。それ以外の場合、セッションレベルのキャッシュが手動でクリアされている場合でも、セッションファクトリーレベルにまだキャッシュがあるため、例外がスローされる場合があります。
2バッチ更新
上記の方法は、バッチ更新データにも適しています。データの複数の行を返す必要がある場合は、scroll()メソッドを使用して、サーバー側のカーソルによってもたらされるパフォーマンスの利点を最大限に活用できます。バッチアップデート用のコードスニペットは次のとおりです。
private void testuser()スロー例外{//セッションセッション= hibernateutil.currentsession(); //トランザクショントランザクションtx = session.begintransaction()を開始します。 //ユーザーテーブルのすべてのレコードscrollableresultsユーザー= session.createquery( "from user").setcachemode(cachemode.ignore).scroll(scrollmode.forward_only); int count = 0; //ユーザーテーブル内のすべてのレコードwhile(users.next()){user u =(user)users.get(0); U.setName( "new username" + count); // countが20の倍数である場合、[++ count%20 == 0){session.flush(); session.clear(); }} tx.commit(); hibernateutil.closeSession();}このようにして、バッチの更新は実行できますが、効果は非常に貧弱です。実行効率は高くなく、最初にデータクエリが必要であり、次にデータの更新が実行されます。この更新は、行ごとの更新です。つまり、レコードの行が更新されるたびに、更新ステートメントを実行する必要があり、パフォーマンスは非常に低いです。
これを回避するために、Hibernateは、バッチアップデートとバッチ削除のためにSQLと同様のHQL構文を提供します。
3 SQLスタイルのバッチアップデート/削除
Hibernateが提供するHQLステートメントは、バッチアップデートと削除構文もサポートしています。
バッチアップデートと削除ステートメントの構文形式は次のとおりです。
更新|削除しますか? className [WHERE_CONDITIONS]
上記の構文形式について注目に値する4つのポイントがあります。
●From句では、Fromキーワードはオプションです。つまり、キーワードから書くことはできません。
●From句にはクラス名が1つしかなく、クラス名にエイリアスを持つことはできません。
●バッチHQLステートメントで接続を使用することはできません。明示的でも暗黙的でもありません。ただし、サブクエリはWhere句で使用できます。
●句全体がオプションです。
ユーザークラスインスタンスの名前属性をバッチ変更する必要があると仮定すると、次のコードスニペットを使用できます。
private void testuser()スロー例外{//セッションセッション= hibernateutil.currentsession(); //トランザクショントランザクションを開始するtx = session.begintransaction(); //バッチ更新hqlステートメント文字列hqlupdate = "ユーザーセットname =:newname"; // update int updateDentities = session.createquery(hqlupdate).setString( "newname"、 "new name").executeUpdate(); //トランザクションtx.commit()をコミットします。 hibernateutil.closeSession();}上記のコードからわかるように、この構文は、準備されたステートメントのexecuteUpdate構文に非常に似ています。実際、HQLのこのバッチアップデートは、SQL構文の更新ステートメントから直接借用しています。
注:このバッチアップデート構文を使用する場合、通常、条件付きレコードを満たすすべての更新を完了するために、SQL更新ステートメントを1回実行する必要があります。ただし、顧客のサブクラスインスタンスがある人がいるなど、継承マッピングなどの特別なケースがあるため、複数の更新ステートメントを実行する必要がある場合があります。バッチが人のインスタンスを更新する場合、顧客インスタンスも更新する必要があります。 Joined-SubclassまたはUnion-Subclassマッピング戦略を使用する場合、個人と顧客のインスタンスが異なるテーブルに保存されるため、複数の更新ステートメントが必要になる場合があります。
hql deleteを実行し、query.executeupdate()メソッドを使用します。以下は、上記のすべてのレコードを一度に削除するコードスニペットです。
private void testuser()throws exception {// open sessionインスタンスセッション= hibernateutil.currentssession(); //トランザクショントランザクションを開始するtx = session.begintransaction(); // batch削除hqlステートメント文字列hqlupdate = "delete user"; // batch削除int updatedentities = session.createquery(hqlupdate).executeupdate(); //トランザクションtx.commit()をコミットします。 //セッションを閉じるhibernateutil.closessession();}Query.executeUpdate()メソッドによって整数値を返します。これは、この操作の影響を受けるレコードの数です。実際、Hibernateの基礎となる操作はJDBCを通じて行われます。したがって、複数の更新または削除ステートメントに変換される更新操作または削除操作のバッチがある場合、メソッドは最後のSQLステートメントの影響を受けるレコードの数を返します。
この記事の説明が、Hibernate Frameworkに基づいた全員のJavaプログラミングに役立つことを願っています。