Hibernateアプリケーションでの一括操作
Hibernateアプリケーションでの一括操作
最近のプロジェクトでは、クエリーを作成するときに大量にデータを更新し、クエリーを行う必要があります.
Hiberanteアプリケーションでは、この更新操作は
一、session.update(object)
1つの方法は、条件に基づいてlistをロードすることです.条件に合致するオブジェクトが1万以上ある場合、sessinキャッシュに複数のオブジェクトがロードされます.
次に、各オブジェクトを1つずつ更新します.トランザクションコミットがキャッシュをクリーンアップし、1万個以上のupdate文を実行する場合
以上の一括更新方式には2つの欠点があります.
(1)大量のメモリを使用する場合、条件を満たすすべてのオブジェクトをメモリにロードしてから、一つ一つ更新する必要があります.
(2)実行されるupdate文の数が多すぎて、update文ごとに1つのCustomerオブジェクトしか更新できず、頻繁にデータベースにアクセスすると、アプリケーションのパフォーマンスが低下します.
üオブジェクトが使用するメモリを迅速に解放するために、各オブジェクトを更新した後、Sessionのevict()メソッドを呼び出して、すぐにそのメモリを解放することができる.
flush()メソッドは、Hibernateが直ちにこのobjectオブジェクトの状態変化に従ってデータベースを同期的に更新し、関連するupdate文を直ちに実行する.evict()メソッドは、このobjectオブジェクトをキャッシュから消去し、使用したメモリをタイムリーに解放するために使用されます.
パフォーマンスを少し向上させることができますが、バッチ操作に影響を与える重要な要素として、数万個のupdate文を生成します.
二、直接sqlを実行する
hibernateがupdate文を実行できる場合、条件に合致するオブジェクトは一度に更新されます.
しかし、Hibernateはこのようなupdate文を実行するインタフェースを直接提供していない.アプリケーションはHibernate APIを迂回し、JDBC APIを介してSQL文を直接実行する必要があります.
以上のプログラムでは,Hibernate APIを迂回してJDBC APIを介して直接データベースにアクセスする手順を示した.アプリケーションは、Sessionのconnection()メソッドで使用するデータベース接続を取得し、PreparedStatementオブジェクトを作成してSQL文を実行します.なお、アプリケーションはHibernateのTransactionインタフェースを介してトランザクション境界を宣言しています.
三、ストレージプロセスの使用
Oracleなどの最下位データベースがストレージ・プロシージャをサポートしている場合は、ストレージ・プロシージャを使用して一括更新を実行することもできます.ストレージ・プロシージャはデータベースで直接実行され、高速化されます.
コールコード
上記のプログラムから、アプリケーションもHibernate APIを迂回して、JDBC APIを直接介してストレージ・プロシージャを呼び出す必要があることがわかります.
四、delete操作
Sessionの様々なリロード形式のupdate()メソッドは、一度に1つのオブジェクトしか更新できませんが、delete()メソッドの一部のリロード形式では、HQL文をパラメータとして使用できます.たとえば、次のようになります.
一括削除は可能ですが、Sessionのdelete()メソッドは次のdelete文を実行していません.
ではなく
Sessionのdelete()メソッドは、次のselect文を使用して、一致するすべてのオブジェクトをメモリにロードします.
次に、N複数のdelete文を実行し、プロジェクトオブジェクトを1つずつ削除します.
したがって,直接Hibernate APIによる一括更新も一括削除も不快である.一方、JDBC APIを直接介して関連するSQL文を実行したり、関連するストレージ・プロシージャを呼び出したりすることは、一括更新と一括削除の最適な方法であり、この2つの方法には以下の利点があります.
(1)データベース内の大量のデータを先にメモリにロードしてから、1つずつ更新したり修正したりする必要がないため、大量のメモリを消費することはありません.
(2)1つのSQL文で大量のデータを更新または削除することができる.
最近のプロジェクトでは、クエリーを作成するときに大量にデータを更新し、クエリーを行う必要があります.
Hiberanteアプリケーションでは、この更新操作は
一、session.update(object)
1つの方法は、条件に基づいてlistをロードすることです.条件に合致するオブジェクトが1万以上ある場合、sessinキャッシュに複数のオブジェクトがロードされます.
次に、各オブジェクトを1つずつ更新します.トランザクションコミットがキャッシュをクリーンアップし、1万個以上のupdate文を実行する場合
tx = session.beginTransaction();
Iterator objects =session.find("from Project where p.id>0").iterator();
while(objects .hasNext()){
Object object=(Object)objects .next();
object.setXXX();
}
tx.commit();
session.close();
以上の一括更新方式には2つの欠点があります.
(1)大量のメモリを使用する場合、条件を満たすすべてのオブジェクトをメモリにロードしてから、一つ一つ更新する必要があります.
(2)実行されるupdate文の数が多すぎて、update文ごとに1つのCustomerオブジェクトしか更新できず、頻繁にデータベースにアクセスすると、アプリケーションのパフォーマンスが低下します.
üオブジェクトが使用するメモリを迅速に解放するために、各オブジェクトを更新した後、Sessionのevict()メソッドを呼び出して、すぐにそのメモリを解放することができる.
tx = session.beginTransaction();
Iterator objects=session.find(“hql").iterator();
while(objects.hasNext()){
Object object =(Object) objects.next();
object.setXXX();
session.flush();
session.evict(customer);
}
tx.commit();
session.close();
flush()メソッドは、Hibernateが直ちにこのobjectオブジェクトの状態変化に従ってデータベースを同期的に更新し、関連するupdate文を直ちに実行する.evict()メソッドは、このobjectオブジェクトをキャッシュから消去し、使用したメモリをタイムリーに解放するために使用されます.
パフォーマンスを少し向上させることができますが、バッチ操作に影響を与える重要な要素として、数万個のupdate文を生成します.
二、直接sqlを実行する
hibernateがupdate文を実行できる場合、条件に合致するオブジェクトは一度に更新されます.
しかし、Hibernateはこのようなupdate文を実行するインタフェースを直接提供していない.アプリケーションはHibernate APIを迂回し、JDBC APIを介してSQL文を直接実行する必要があります.
tx = session.beginTransaction();
Connection con=session.connection();
PreparedStatement stmt=con.prepareStatement(sql");
stmt.executeUpdate();
tx.commit();
以上のプログラムでは,Hibernate APIを迂回してJDBC APIを介して直接データベースにアクセスする手順を示した.アプリケーションは、Sessionのconnection()メソッドで使用するデータベース接続を取得し、PreparedStatementオブジェクトを作成してSQL文を実行します.なお、アプリケーションはHibernateのTransactionインタフェースを介してトランザクション境界を宣言しています.
三、ストレージプロセスの使用
Oracleなどの最下位データベースがストレージ・プロシージャをサポートしている場合は、ストレージ・プロシージャを使用して一括更新を実行することもできます.ストレージ・プロシージャはデータベースで直接実行され、高速化されます.
create or replace procedure updateProject is
begin
update project p set p.total_intend_gather =
(select sum(ig.gather_sum) from intend_gather ig where ig.project_number=p.project_number);
update project p set p.total_actual_gather =
(select sum(ag.gahter_sum) from actual_gather ag where ag.project_number=p.project_number);
update project p set p.total_invoice=
(select sum(invoice.invoice_sum) from invoice invoice
where invoice.intend_id in
(select ig.intend_id from intend_gather ig where ig.project_number=p.project_number));
end updateProject;
コールコード
Session session = this.getSession();
Transaction tx =null;
try {
tx = session.beginTransaction();
Connection con = session.connection();
String procedure = "{call updateproject() }";
CallableStatement cstmt = con.prepareCall(procedure);
cstmt.executeUpdate();
tx.commit();
} catch (Exception e) {
tx.rollback();
}
上記のプログラムから、アプリケーションもHibernate APIを迂回して、JDBC APIを直接介してストレージ・プロシージャを呼び出す必要があることがわかります.
四、delete操作
Sessionの様々なリロード形式のupdate()メソッドは、一度に1つのオブジェクトしか更新できませんが、delete()メソッドの一部のリロード形式では、HQL文をパラメータとして使用できます.たとえば、次のようになります.
session.delete(from Project where p.id>0);
一括削除は可能ですが、Sessionのdelete()メソッドは次のdelete文を実行していません.
delete from PROJECT where ID>0;
ではなく
Sessionのdelete()メソッドは、次のselect文を使用して、一致するすべてのオブジェクトをメモリにロードします.
select * from Project where ID>0;
次に、N複数のdelete文を実行し、プロジェクトオブジェクトを1つずつ削除します.
delete from PROJECT where ID=i;
delete from PROJECT where ID=j;
delete from PROJECT where ID=k;
したがって,直接Hibernate APIによる一括更新も一括削除も不快である.一方、JDBC APIを直接介して関連するSQL文を実行したり、関連するストレージ・プロシージャを呼び出したりすることは、一括更新と一括削除の最適な方法であり、この2つの方法には以下の利点があります.
(1)データベース内の大量のデータを先にメモリにロードしてから、1つずつ更新したり修正したりする必要がないため、大量のメモリを消費することはありません.
(2)1つのSQL文で大量のデータを更新または削除することができる.