| 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 Calculator.java iステートレスセッションBeanインタフェースです UpdateCalculatorBean.java データベース更新の実行を実装するセッションBeanです JSPユーザインタフェース update.jsp
まとめ
| このトレイルでは、データベースの更新方法を学習しました。データベース同期戦略と更新されていないエンティティBeanインスタンスのマージについても議論しました。つまり、EJB 3.0では、データベース同期はコンテナのトランザクションマネージャによって管理されるのです。後で登場するトランザクションのトレイルでは、トランザクションマネージャがどのように動作するかについて学びます。次のトレイルでは、エンティティBeanのライフサイクルコールバックについて手短に学びましょう