Spring と Hibernate を使用して複数のデータベース間で分散トランザクションを実行する「最良の」方法は何ですか?
-
02-07-2019 - |
質問
私は隅に置いて 2 つの異なるデータベースを定期的に更新する、ユーティリティに近いアプリケーションを持っています。
これは、Spring アプリケーション コンテキストを使用して構築された小さなスタンドアロン アプリです。コンテキストには 2 つの Hibernate セッション ファクトリが構成されており、Spring で構成された Commons DBCP データ ソースを使用します。
現在トランザクション管理はありませんが、いくつか追加したいと思います。一方のデータベースの更新は、他方のデータベースの更新が成功するかどうかに依存します。
アプリは Java EE コンテナー内には存在しません。シェル スクリプトから呼び出される静的ランチャー クラスによってブートストラップされます。ランチャー クラスはアプリケーション コンテキストをインスタンス化し、その Bean の 1 つでメソッドを呼び出します。
データベースの更新にトランザクション性を持たせるための「最善の」方法は何ですか?
「最良」の定義は皆さんにお任せしますが、「セットアップが簡単」、「設定が簡単」、「安価」、「パッケージ化と再配布が簡単」という何らかの機能であるべきだと思います。当然FOSSが良いでしょう。
解決
トランザクションを複数のデータベースに分散する最良の方法は次のとおりです。やめてください。
XA を指摘する人もいますが、XA (または 2 フェーズ コミット) は嘘 (または市場用語) です。
想像する:最初のフェーズで XA マネージャーに最終コミットを送信できることを通知した後、データベースの 1 つへのネットワーク接続が失敗します。それで?タイムアウト?これにより、他のデータベースが破損したままになります。ロールバックしますか?2 つの問題:コミットをロールバックすることはできません。2 番目のデータベースに何が起こったのかをどうやって知ることができるでしょうか?おそらく、データを正常にコミットした後にネットワーク接続が失敗し、「成功」メッセージだけが失われてしまったのでしょうか?
最善の方法は、データを 1 か所にコピーすることです。いつでもコピーを中止して続行できるスキームを使用します (たとえば、既に持っているデータを無視するか、ID による選択を順序付けて、コピーの MAX(ID) を超えるレコードのみを要求します)。これをトランザクションで保護します。ソースからデータを読み取るだけなので、これは問題ではありません。そのため、何らかの理由でトランザクションが失敗した場合は、ソース データベースを無視できます。したがって、これは単純な古い単一ソース トランザクションです。
データをコピーした後、ローカルで処理します。
他のヒント
コンテキスト内でトランザクション マネージャーをセットアップします。Spring のドキュメントには例があり、非常に簡単です。次に、トランザクションを実行する場合は次のようにします。
try {
TransactionTemplate tt = new TransactionTemplate(txManager);
tt.execute(new TransactionCallbackWithoutResult(){
protected void doInTransactionWithoutResult(
TransactionStatus status) {
updateDb1();
updateDb2();
}
} catch (TransactionException ex) {
// handle
}
より多くの例と情報については、おそらくこれを参照してください。Spring を使用した XA トランザクション
「2 つの異なるデータベース」という場合、異なるデータベース サーバー、または同じ DB サーバー内の 2 つの異なるスキーマを意味しますか?
前者の場合、完全なトランザクション性が必要な場合は、完全な 2 フェーズ コミットを提供する XA トランザクション API が必要です。しかし、より重要なのは、異なるデータベース システム間のトランザクションの伝播を管理するトランザクション コーディネーター/モニターも必要であるということです。これは JavaEE 仕様の一部ですが、その中でもかなり希少な部分です。TX コーディネーター自体は複雑なソフトウェアです。アプリケーション ソフトウェアは (必要に応じて Spring 経由で) コーディネーターと通信します。
ただし、同じ DB サーバー内の 2 つのデータベースを意味する場合は、単一のトランザクション内で両方のデータベースに対して操作を実行するだけで、通常の JDBC トランザクションは問題なく動作するはずです。
この場合、トランザクション モニター (XA プロトコルをサポートするサーバー) が必要になり、データベースも XA をサポートしていることを確認します。ほとんど (すべて?) J2EE サーバーにはトランザクション モニターが組み込まれています。コードが J2EE サーバー以外で実行されている場合は、Atomicos、Bitronix などのスタンドアロンの代替手段が多数あります。
Spring ChainedTransactionManager を試すことができます - http://docs.spring.io/spring-data/commons/docs/1.6.2.RELEASE/api/org/springframework/data/transaction/ChainedTransactionManager.html 分散データベーストランザクションをサポートします。これは XA のより良い代替手段となる可能性があります