JBoss EJB 3.0と拡張機能

  データベースの更新と同期
はじめに

EJB 3.0コンテナはエンティティBeanオブジェクトを直接操作することでデータベース内のデータ行を更新可能にします。その変更は自動的にキューに蓄積され(queued)、データベースに送出されます。このトレイルでは、まさしくデータベースが更新が機能する様子を学びます。

サンプルアプリケーション

データベース更新を説明するため、投資計算機にTimedRecordテーブル内のすべてのドルの値を別の通貨(currency)へ更新する新機能を実装します。やらなければならないことは、次のフォームの為替変換レートを入力して「更新」ボタンをクリックするだけです。

更新プロセス

テーブルの複数行を更新するには、最初にEntityManager APIによってそれらの行をエンティティBeanへ取得すべきです。そうすれば、(データベース内のテーブルカラムにマップされる)任意のデータ属性の更新をするのに、通常のセッターメソッドを使うだけで可能になります。


@Stateless
public class UpdateCalculator implements Calculator {

  @PersistenceContext
  protected EntityManager em;

  // ... ...

  public void updateExchangeRate (double newrate) {
    Collection <TimedRecord> rc = 
      em.createQuery("from TimedRecord r").getResultList();
    for (Iterator iter = rc.iterator(); iter.hasNext();) {
      TimedRecord r = (TimedRecord) iter.next();
      r.setSaving(r.getSaving() * newrate);
      r.setResult(r.getResult() * newrate);
    }
  }
}
データベースとの同期

updateExchangeRate()メソッドでは、すべての計算記録Beanインスタンスを更新するためにループを使っていました。しかし、ループ内で各Beanを更新するためにコンテナがデータベースに対してリモートのSQL更新を送信するというのは遅くて効率が悪いことです。何回もデータベースにアクセスすることは、ネットワークエラーの機会を増大させ、データベースの負荷を増大させます。より良い方法は、キューに更新を蓄積し、ループが終了した後でバッチによってそれらの要求をデータベースと同期させるという方法です。これはコンテナがこのケースでまさに実行していたことです。

デフォルトでは、すべてのEntityManager操作(新規Beanの永続化、Beanの削除、Beanの更新)は、メモリ上にキャッシュされます。それらは現在スレッド(つまり、メソッド呼び出しスタック)が完了したとき、あるいは次のデータベース問合せが発行される前、のいずれか早い方で、単一のバッチによってデータベースとの同期が行われます。例では、コンテナはupdateExchangeRate()メソッドが完了した直後にすべてのBeanオブジェクトはデータベースと同期させられます。

しかし、ユーザによっては、スレッド内でのデータベース同期のタイミングを手動で正確に制御し、最適化したいと望むかもしれません。例えば、クラスタ内でメモリを削減し、大きなキャッシュ複製を避けるため、早期に変更を送信したいと望むかもしれません。トランザクション内では、EntityManager.flush()メソッドを呼び出すことによって、EntityManager内の現在のイン・メモリ(in-memory)変更をデータベースに対してフラッシュすることが可能です。EntityManager のフラッシュは、メソッドの途中やコールスタックの途中でのメソッドの最後(つまり、スレッドの途中)で可能です。

エンティティBeanのデータベースへのマージ

ローカルEntityManagerは取得済みのエンティティBeanの記録を取り、データベースへの同期が必要となるようなBeanオブジェクトへのすべての更新情報を捕捉します。しかし、ローカルEntityManagerから得ることができないエンティティBeanインスタンスについてはどうすればよいのでしょうか。例えば、TimedRecord Beanがネットワーク接続を介してシリアライズされていたとしたらどうしますか。どうやってそれを更新したり、データベースへ同期すべき変更を取得したりできるのでしょう。それをするには、EntityManager.merge()メソッドを使って、その呼び出しパラメタとしてBeanインスタンスを渡すことができるのです。

一般的には、ローカルスレッド以外から得たエンティティBeanを更新するなら、EntityManager.merge()を呼び出してその値をデータベースへ書き戻してマージする必要があります。

ソースコード参照

セッションBean

JSPユーザインタフェース

まとめ

このトレイルでは、データベースの更新方法を学習しました。データベース同期戦略と更新されていないエンティティBeanインスタンスのマージについても議論しました。つまり、EJB 3.0では、データベース同期はコンテナのトランザクションマネージャによって管理されるのです。後で登場するトランザクションのトレイルでは、トランザクションマネージャがどのように動作するかについて学びます。次のトレイルでは、エンティティBeanのライフサイクルコールバックについて手短に学びましょう