18

Hibernate を使用して Oracle データベースにアクセスしています。

Hibernate の第 1 レベル (またはセッション) キャッシュに問題があると思います。アカウントを表すテーブルがあります: ACCOUNT テーブル、INVOICE テーブル、および PAYMENTS テーブルです。PAYMENT を追加すると、関連する INVOICE および ACCOUNT テーブルの列が自動的に更新されるように、Oracle データベースで定義されたプロシージャがあります。

私が抱えている問題は、Hibernate を使用して次のようなことを行う場合です。

Account account = accountDao.get(accountId);
assertEquals(0.00, account.getBalance());

// Saving a payment will trigger stored procedures that 
// will update the account balance.
paymentDao.save(createPaymentForAccount(accountId, 20.00));

account = accountDao.get(accountId);
assertEquals(20.00, account.getBalance()); 

ではなく がaccount.getBalance()返されるため、最後のアサーションは失敗します。0.0020.00

2 番目の呼び出しaccountDao.get(...)でデータベースにアクセスし、新しい ACCOUNT オブジェクトを取得します。しかし、Hibernate は既にキャッシュにあるアカウント オブジェクトを返すように見えます (lookup 呼び出しのデバッグ出力を調べると、 が表示されますnumber of objects hydrated: 0)。

Hibernate は、ストアド プロシージャの呼び出しのためにデータベースが変更されたことを認識していないと思います。これが、オブジェクトをキャッシュ内で使用する理由です。

そこで、解決策を考え始めました。1 つは、PAYMENT が保存されるたびに、休止状態のセッション キャッシュから ACCOUNT および PAYMENT オブジェクトを削除することです。これにより、ACCOUNT または INVOICE 操作のデータベース フェッチが (新しく更新された値で) 強制されます。

私は次のことを試しました:

public void save(Payment payment) {
  getSession().persist(payment);
  getSessionFactory().evict(Invoice.class);
  getSessionFactory().evict(Account.class);
}

しかし、休止状態のトレース ログは何も起こらなかったことを示していました。sessionFactory.evict(...)これは有効になっていない第 2 レベルのキャッシュで動作するため、削除するものは何もないと思います。

次に、見つかった各インスタンスを削除して、セッション キャッシュからすべての ACCOUNT オブジェクトと INVOICE オブジェクトを削除しようとしました。

public void save(Payment payment) {
  getSession().persist(payment);
  for (Invoice invoice: lookupInvoices()) { // e.g. "from Invoice" query
    getSession().evict(invoice);
  }
  for (Account account: lookupAccounts()) { // e.g. "from Account" query
    getSession().evict(account);
  }
}

これは機能しているように見えますが、すべてのインスタンスを削除する前に休止状態のセッション キャッシュにロードするため、非常に非効率的です。

指定されたタイプのすべてのオブジェクトの第 1 レベルのキャッシュをクリアする方法がわかりません。他にどのような解決策がありますか?

4

2 に答える 2

12

session.refresh() メソッドを使用できます。11.3を参照してください。ドキュメントにオブジェクトをロードします。

于 2013-06-05T00:33:08.613 に答える