検索

第11章 Jakarta Transactions

download PDF

11.1. 概要

11.1.1. Jakarta トランザクションの概要

はじめに

ここでは、Jakarta Transaction の基礎的な内容について取り上げます。

11.2. トランザクションの概念

11.2.1. トランザクション

トランザクションは 2 つ以上のアクションで構成されており、アクションすべてが成功または失敗する必要があります。成功した場合はコミット、失敗した場合はロールバックが結果的に実行されます。ロールバックでは、トランザクションがコミットを試行する前に、各メンバーの状態が元の状態に戻ります。

よく設計されたトランザクションの通常の標準は Atomic, Consistent, Isolated, and Durable (ACID) です。

11.2.2. トランザクションの ACID プロパティー

ACID は 原子性 (Atomicity)、一貫性 (Consistency)、独立性 (Isolation)、永続性 (Durability) の略語です。通常、この用語はデータベースやトランザクション操作において使用されます。

原子性 (Atomicity)
トランザクションの原子性を保つには、すべてのトランザクションメンバーが同じ決定を行う必要があります。これらのメンバーはコミットまたはロールバックを行います。原子性が保たれない場合の結果はヒューリスティックな結果と呼ばれます。
一貫性
一貫性とは、データベーススキーマの観点から、データベースに書き込まれたデータが有効なデータであることを保証するという意味です。データベースあるいは他のデータソースは常に一貫した状態でなければなりません。一貫性のない状態の例には、操作が中断される前にデータの半分が書き込まれてしまったフィールドなどがあります。すべてのデータが書き込まれた場合や、書き込みが完了しなかった時に書き込みがロールバックされた場合に、一貫した状態となります。
分離
独立性とは、トランザクションのスコープ外のプロセスがデータを変更できないように、トランザクションで操作されたデータが変更前にロックされる必要があることを意味します。
持続性 (Durability)
持続性とは、トランザクションのメンバーがコミットするよう指示されてから外部で問題が発生した場合に、問題が解決されるとすべてのメンバーがトランザクションを継続してコミットできることを意味します。このような問題には、ハードウェア、ソフトウェア、ネットワーク、またはその他の関与するシステムが関連することがあります。

11.2.3. トラザクションコーディネーターまたはトランザクションマネージャー

JBoss EAP のトランザクションでは、トランザクションコーディネーターとトランザクションマネージャー™ という言葉は、ほとんど同じことを意味します。トランザクションコーディネーターという言葉は通常、分散 JTS トランザクションのコンテキストで使用されます。

Jakarta Transactions トランザクションでは、TM は JBoss EAP 内で実行され、2 フェーズコミットのプロトコルでトランザクションの参加者と通信します。

TM はトランザクションの参加者に対して、他のトランザクションの参加者の結果に従い、データをコミットするか、ロールバックするか指示します。こうすることで、確実にトランザクションが ACID 標準に準拠するようにします。

11.2.4. トランザクションの参加者

トランザクションの参加者は、状態をコミットまたはロールバックできるトランザクション内のリソースであり、一般的にデータベースまたは JMS ブローカーを生成します。これは通常データベースや Jakarta Messaging ブローカーです。ただし、トランザクションインターフェースを実装することにより、アプリケーションコードがトランザクションの参加者として動作することもできます。トランザクションの各参加者は、状態をコミットまたはロールバックできるかどうかを独自に決定します。そして、すべての参加者がコミットできる場合のみ、トランザクション全体が成功します。コミットできない参加者がある場合は、各参加者がそれぞれの状態をロールバックし、トランザクション全体が失敗します。TM は、コミットおよびロールバック操作を調整し、トランザクションの結果を判断します。

11.2.5. Jakarta Transactions について

Jakarta Transactions は Jakarta EE Spec 一部です。Jakarta Transactions 1.3 Specification で定義されています。

Jakarta Transactions の実装は、JBoss EAP アプリケーションサーバーの Narayana プロジェクトに含まれる TM を使用して実行されます。TM により、単一のグローバルトランザクションを使用してアプリケーションがさまざまなリソース (データベースや Jakarta Messaging ブローカーなど) を割り当てできるようになります。グローバルトランザクションは XA トランザクションと呼ばれます。一般的に、このようなトランザクションには XA 機能を持つリソースが含まれますが、XA 以外のリソースがグローバルトランザクションに含まれることもあります。非 XA リソースを XA 対応リソースとして動作させるのに役に立つ複数の最適化があります。詳細は、「1 フェーズコミット (1PC) の LRCO 最適化」を参照してください。

本書では、Jakarta Transactions という用語は以下の 2 つを指します。

  1. Jakarta EE 仕様で定義されている Jakarta Transactions。
  2. TM がトランザクションをどのように処理するかを示します。

TM は Jakarta Transactions トランザクションモードで動作し、データはメモリーで共有されます。また、トランザクションコンテキストはリモート Jakarta Enterprise Beans 呼び出しによって転送されます。管理トランザクションモードでは、データは CORBA (Common Object Request Broker Architecture) メッセージを送信して共有され、トランザクションコンテキストは IIOP 呼び出しによって転送されます。複数の JBoss EAP サーバー上におけるトランザクションの分散は両方のモードでサポートされます。

11.2.6. JTS について

JTS は Object Transaction Service (OTS) から Jakarta へのマッピングです。Jakarta EE アプリケーションは Jakarta Transactions を使用してトランザクションを管理します。その後、トランザクションマネージャーが JTS モードに切り替わると、Jakarta Transactions は Object Transactions Service トランザクション実装と対話します。JTS は IIOP プロトコル上で動作します。JTS を使用するトランザクションマネージャーは Object Request Broker (ORB) と呼ばれるプロセスと Common Object Request Broker Architecture (CORBA) と呼ばれる通信標準を使用してお互いに通信します。詳細は、JBoss EAP『設定 ガイド』 の「 ORB 設定 」を参照してください。

アプリケーションの観点で Jakarta Transactions を使用すると、JTS トランザクションは Jakarta Transactions トランザクションと同じように動作します。

注記

JBoss EAP に含まれる JTS の実装は、分散トランザクションをサポートします。完全準拠の JTS トランザクションとの違いは、外部のサードパーティー ORB との相互運用性です。この機能は、JBoss EAP ではサポートされません。サポートされる設定では、複数の JBoss EAP コンテナーでのみトランザクションが分散されます。

11.2.7. XML トランザクションサービス

XML トランザクションサービス (XTS) コンポーネントは、ビジネストランザクションのプライベートおよびパブリック web サービスの調整をサポートします。XTS を使用すると、複雑なビジネストランザクションを制御され信頼できる状態で調整できます。XTS API は WS-Coordination、WS-Atomic Transaction、および WS-Business Activity プロトコルを基にしたトランザクションコーディネーションモデルをサポートします。

11.2.7.1. XTS によって使用されるプロトコルの概要

WS-Coordination (WS-C) 仕様は、異なるコーディネーションプロトコルがプラグインできるようにするフレームワークを定義し、クライアント、サービス、および参加者の間で作業を調整します。

WS-Transaction (WS-T) プロトコルは、WS-C によって提供されるコーディネーションフレームワークを利用する WS-Atomic Transaction (WS-AT) および WS-Business Activity (WS-BA) の 2 つのトランザクションコーディネーションプロトコルで構成されます。WS-T は、既存の従来のトランザクション処理システムを統一するために開発され、これらのシステム間で確実に通信が行われるようにします。

11.2.7.2. Web Services-Atomic Transaction (WS-AT) プロセス

アトミックトランザクション (AT) は、ACID セマンティックが適切である場合に短期間の対話をサポートするよう設計されています。AT の範囲内では、web サービスは通常 WS-T の制御下でブリッジングを用いてデータベースやメッセージキューなどの XA リソースにアクセスします。トランザクションが終了すると、参加者は AT の決定結果を XA リソースに伝搬し、各参加者によって適切なコミットまたはロールバックが実行されます。

11.2.7.2.1. アトミックトランザクション (AT) プロセス
  1. AT を開始する際、クライアントは最初に WS-T をサポートする WS-C Activation Coordinator web サービスを見つけます。
  2. クライアントは、http://schemas.xmlsoap.org/ws/2004/10/wsat をコーディネーション型として指定して、WS-C CreateCoordinationContext メッセージをサービスに送信します。
  3. クライアントは適切な WS-T コンテキストをアクティベーションサービスから受け取ります。
  4. CreateCoordinationContext メッセージの応答であるトランザクションコンテキストの CoordinationType 要素は、WS-AT ネームスペース http://schemas.xmlsoap.org/ws/2004/10/wsat に設定されています。また、参加者を登録できるアトミックトランザクションコーディネーターエンドポイントである WS-C Registration Service への参照も含まれます。
  5. クライアントは通常、続いて Web サービスの呼び出しを行い、Web サービスによるすべての変更をコミットまたはロールバックしてトランザクションを完了します。完了できるようにするには、エンドポイントがコーディネーションコンテキストで返された登録サービスに登録メッセージを送信し、クライアントを完了プロトコルの参加者として登録する必要があります。
  6. クライアントを登録したら、クライアントアプリケーションは web サービスと対話してビジネスレベルの作業を達成します。クライアントは、ビジネス web サービスが呼び出されるごとに、トランザクションコンテキストを SOAP ヘッダーブロックの挿入し、各呼び出しがトランザクションによって暗黙的にスコープ付けされます。WS-AT 対応 web サービスをサポートするツールキットは、SOAP ヘッダーブロックで見つかったコンテキストをバックエンド操作と関連付ける機能を提供します。これにより、web サービスによる変更がクライアントと同じトランザクションの範囲内で行われるようにし、トランザクションコーディネーターによるコミットまたはロールバックの対象になるようにします。
  7. 必要なアプリケーションの作業がすべて完了したら、クライアントはサービス状態の変更を永続する目的でトランザクションを終了することができます。完了参加者は、トランザクションをコミットまたはロールバックするようコーディネーターに指示します。コミットまたはロールバック操作が完了すると、トランザクションの結果を示すために状態が参加者に返されます。

詳細は、『Naryana Project Documentation』の「WS-Coordination」を参照してください。

11.2.7.2.2. Microsoft .NET クライアントとの WS-AT の相互運用性

WS-AT 仕様の .NET 実装の違いにより、xts サブシステムと Microsoft .NET クライアントとの通信に問題が発生することがあります。WS-AT 仕様の .NET 実装はすべての呼び出しが非同期になるよう強制します。

.NET クライアントとの相互運用性を有効にするため、JBoss EAP の xts サブシステムでは非同期登録のオプションを利用できます。XTS 非同期登録はデフォルトでは無効になっており、必要な場合のみ有効にする必要があります。

非同期登録を有効にして .NET クライアントとの WS-AT の相互運用性を維持するには、以下の管理 CLI コマンドを実行します。

/subsystem=xts:write-attribute(name=async-registration, value=true)

11.2.7.3. Web Services-Business Activity (WS-BA) プロセス

Web Services-Business Activity (WS-BA) は、既存のビジネスプロセスおよびワークフローシステムがプロプライエタリーメカニズムをラップし、実装およびビジネス境界全体で相互運用できるようにする、web サービスアプリケーションのプロトコルを定義します。

要求時のみ参加者が状態をトランザクションコーディネーターに伝える WS-AT プロトコルモデルとは異なり、WS-BA 内の子アクティビティーは要求を待たずに結果を直接コーディネーターに指定できます。参加者はいつでもアクティビティーを終了するかコーディネーターへ失敗を通知するかを選択できます。失敗を特定するためにトランザクションの最後まで待たずに、通知を使用してゴールを編集し、処理を継続できるため、この機能はタスクが失敗したときに便利です。

11.2.7.3.1. WS-BA プロセス
  1. サービスは作業をするよう要求されます。
  2. これらのサービスに作業を元に戻す機能があるのであれば、WS-BA が後でその作業の取り消しを決定した場合に備えて WS-BA に通知します。WS-BA に障害が発生した場合は、元に戻す undo 動作を実行するようサービスに指示することができます。

WS-BA プロトコルは補正ベースのトランザクションモデルを利用します。ビジネスアクティビティーの参加が作業を完了すると、アクティビティーを終了することを選択できます。この選択は、その後のロールバックを許可しません。この代わりに、参加者はアクティビティーを完了し、後で別の参加者が障害をコーディネーターに通知した場合に、行った作業を補正できることをコーディネーターに伝えることができます。この場合、コーディネーターは終了していない各参加者に障害を補正するよう要求し、適切であると見なされる補正アクションを実行する機会を与えます。すべての参加者が障害なしで終了または完了した場合、コーディネーターは完了した各参加者に対してアクティビティーがクローズしたことを通知します。

詳細は、『Naryana Project Documentation』の「WS-Coordination」を参照してください。

11.2.7.4. トランザクションブリッジングの概要

トランザクションブリッジングは、Jakarta EE と WS-T ドメインをリンクするプロセスを説明します。トランザクションブリッジコンポーネントである txbridge は双方向のリンクを提供し、トランザクションのいずれの型も、別の型と使用するよう設計されているビジネスロジックを含めることができます。ブリッジによって使用される技術は、介入とプロトコルマッピングの組み合わせです。

トランザクションブリッジでは、介入されるコーディネーターは既存のトランザクションに登録され、プロトコルマッピングの追加タスクを実行します。 これらのトランザクション型が異なっても、その親コーディネーターに対してはネイティブトランザクション型のリソースとして見られ、その子に対してはネイティブトランザクション型のコーディネーターとして見られます。

トランザクションブリッジは org.jboss.jbossts.txbridge パッケージとそのサブパッケージにあります。これは、クラスの 2 つのセットによって構成され、セットごとに各方向のブリッジング用になります。

詳細は、『Naryana Project Documentation』の「TXBridge Guide」を参照してください。

11.2.8. XA リソースおよび XA トランザクション

XA は eXtended Architecture を表し、複数のバックエンドデータストアを使用するトランザクションを定義するために X/Open Group によって開発されました。XA 標準は、グローバル TM とローカルリソースマネージャーとの間のインターフェースを定義します。XA では、4 つの ACID プロパティーすべてを保持しながらアプリケーションサーバー、データベース、キャッシュ、メッセージキューなどの複数のリソースが同じトランザクションに参加できるようにします。4 つの ACID プロパティーの 1 つは原子性であり、これは参加者の 1 つが変更のコミットに失敗した場合に他の参加者がトランザクションを中止し、トランザクションが発生する前の状態に戻すことを意味します。XA リソースは XA グローバルトランザクションに参加できるリソースです。

XA トランザクションは、複数のリソースにまたがることができるトランザクションです。これには、コーディネートを行う TM が関係します。 この TM は、すべてが 1 つのグローバル XA トランザクションに関与する 1 つ以上のデータベースまたは他のトランザクションリソースを持ちます。

11.2.9. XA リカバリー

TM は X/Open XA 仕様を実装し、複数の XA リソースで XA トランザクションをサポートします。

XA リカバリーは、トランザクションの参加者であるリソースのいずれかがクラッシュしたり使用できなくなったりしても、トランザクションの影響を受けたすべてのリソースが確実に更新またはロールバックされるようにするプロセスのことです。JBoss EAP の範囲内では、XA データソース、Jakarta Messaging メッセージキュー、Jakarta Connector リソースアダプターなどの XA リソースまたはサブシステムに対して、transactions サブシステムが XA リカバリーのメカニズムを提供します。

XA リカバリーはユーザーの介入がなくても実行されます。XA リカバリーに失敗すると、エラーがログ出力に記録されます。サポートが必要な場合は、Red Hat グローバルサポートサービスまでご連絡ください。XA リカバリープロセスは、デフォルトで 2 分ごとに開始される定期リカバリースレッドにより開始されます。定期リカバリースレッドにより、未完了のすべてのトランザクションが処理されます。

注記

未確定なトランザクションのリカバリーを完了するには 4 -8 分ほどかかることがあります。 これはリカバリープロセスを複数回実行する必要がある場合があるためです。

11.2.10. XA リカバリープロセスの制限

XA リカバリーには以下の制限があります。

  • トランザクションログが正常にコミットされたトランザクションから消去されないことがあります。

    XAResource のコミットメソッドが正常に完了し、トランザクションをコミットした後、コーディネーターがログをアップデートできるようになる前に JBoss EAP サーバーがクラッシュした場合、サーバーの再起動時に以下の警告メッセージが表示されることがあります。

    ARJUNA016037: Could not find new XAResource to use for recovering non-serializable XAResource XAResourceRecord

    これは、リカバリー時に JBoss トランザクションマネージャー (TM) はログのトランザクション参加者を確認し、コミットを再試行しようとするからです。最終的に、JBoss TM はリソースがコミットされたと見なし、コミットを再試行しなくなります。このような場合、トランザクションはコミットされデータの損失はないため、警告を無視しても問題ありません。

    警告が表示されないようにするには、com.arjuna.ats.jta.xaAssumeRecoveryComplete プロパティーの値を true に設定します。このプロパティーは、登録された XAResourceRecovery インスタンスから新しい XAResource インスタンスが見つからないとチェックされます。true に設定すると、リカバリーで、以前のコミットの試行が成功したと見なされ、これ以上リカバリーを試行しなくてもインスタンスをログから削除できます。このプロパティーはグローバルであり、適切に使用しないと XAResource インスタンスがコミットされていない状態のままになるため、注意して使用する必要があります。

    注記

    JBoss EAP 7.4 には、トランザクションが正常にコミットされた後にトランザクションログを消去する拡張機能が実装されているため、上記の状況は頻繁に発生しません。

  • XAResource.prepare() の最後にサーバーがクラッシュすると、JTS トランザクションに対するロールバックは呼び出されません。

    XAResource.prepare() メソッド呼び出しの完了後に JBoss EAP サーバーがクラッシュすると、参加している XAResource インスタンスはすべて準備済みの状態でロックされ、サーバーの再起動時にその状態を維持します。トランザクションがタイムアウトするか、データベース管理者が手動でリソースをロールバックしてトランザクションログを消去するまで、トランザクションはロールバックされずリソースはロックされたままになります。詳細は、「https://issues.jboss.org/browse/JBTM-2124」を参照してください。

  • 周期リカバリーはコミットされたトランザクションで発生する可能性があります。

    サーバーに過剰な負荷がかかっている場合、サーバーログには以下の警告メッセージとそれに続くスタックトレースが含まれる場合があります。

    ARJUNA016027: Local XARecoveryModule.xaRecovery got XA exception XAException.XAER_NOTA: javax.transaction.xa.XAException

    負荷が大きい場合、トランザクションにかかる処理時間が周期的リカバリープロセスのアクティビティーと重なることがあります。周期的リカバリープロセスは進行中のトランザクションを検出し、ロールバックを開始しようとしますが、トランザクションは完了するまで続行されます。周期的リカバリーはロールバックの開始に失敗し、ロールバックの失敗がサーバーログに記録されます。この問題の根本的な原因は、今後のリリースで修正される予定ですが、現時点では回避方法を使用できます。

    com.arjuna.ats.jta.orphanSafetyInterval プロパティーの値をデフォルト値の 10000 ミリ秒よりも大きくし、リカバリープロセスの 2 つのフェーズの間隔を増やします。40000 ミリ秒の値が推奨されます。この設定では問題は解決されないことに注意してください。問題が発生して警告メッセージがログに記録される可能性が減少します。詳細は、「https://developer.jboss.org/thread/266729」を参照してください。

11.2.11. 2 フェーズコミットプロトコル

2 フェーズコミット (2PC) プロトコルは、トランザクションの結果を決定するアルゴリズムを参照します。2PC は XA トランザクションを完了するプロセスとしてトランザクションマネージャー (TM) によって開始されます。

フェーズ 1: 準備

最初のフェーズでは、トランザクションをコミットできるか、あるいはロールバックする必要があるかをトランザクションの参加者がトランザクションコーディネーターに通知します。

フェーズ 2: コミット

2 番目のフェーズでは、トランザクションコーディネーターがトランザクション全体をコミットするか、またはロールバックするかを決定します。いずれの参加者もコミットできない場合、トランザクションはロールバックしなければなりません。それ以外の場合、トランザクションはコミットできます。コーディネーターは何を行うかをリソースに指示し、リソースはその完了時にコーディネーターに通知します。この時点で、トランザクションは完了します。

11.2.12. トランザクションタイムアウト

原子性を確保し、トランザクションを ACID 標準に準拠させるために、トランザクションの一部が長期間実行される場合があります。トランザクションの参加者は、コミット時にデータベーステーブルまたはキュー内のメッセージの一部である XA リソースをロックする必要があります。また、TM は各トランザクション参加者からの応答を待ってからすべての参加者にコミットあるいはロールバックの指示を出す必要があります。ハードウェアあるいはネットワークの障害のため、リソースが永久にロックされることがあります。

トランザクションのタイムアウトをトランザクションと関連付け、ライフサイクルを制御することができます。タイムアウトのしきい値がトランザクションのコミットあるいはロールバック前に渡された場合、タイムアウトにより、自動的にトランザクションがロールバックされます。

トランザクションサブシステム全体に対しデフォルトのタイムアウト値を設定できます。 または、デフォルトのタイムアウト値を無効にし、トランザクションごとにタイムアウトを指定できます。

11.2.13. 分散トランザクション

分散トランザクションは、複数の JBoss EAP サーバー上に参加者が存在するトランザクションです。JTS 仕様では、異なるベンダーのアプリケーションサーバー間で JTS トランザクションを分散可能にすることが規定されています。Jakarta Transactions はこれを定義しませんが、JBoss EAP は JBoss EAP サーバー間の分散 Jakarta Transactions トランザクションをサポートします。

注記

異なるベンダーのサーバー間でのトランザクション分散はサポートされません。

注記

他のベンダーのアプリケーションサーバーのドキュメントでは、分散トランザクションという用語が XA トランザクションを意味することがあります。JBoss EAP のドキュメントでは、複数の JBoss EAP アプリケーションサーバー間で分散されるトランザクションを分散トランザクションと呼びます。また、本書では、異なるリソースで構成されるトランザクション (データベースリソースや Jakarta Messaging リソースなど) を XA トランザクションと呼びます。詳細は、「JTS について」および「XA データソースおよび XA トランザクション」を参照してください。

11.2.14. ORB 移植性 API

Object Request Broker (ORB) とは、複数のアプリケーションサーバーで分散されるトランザクションの参加者、コーディネーター、リソース、および他のサービスにメッセージを送受信するプロセスのことです。ORB は標準的なインターフェース記述言語 (IDL) を使用してメッセージを通信し解釈します。Common Object Request Broker Architecture (CORBA) は JBoss EAP の ORB によって使用される IDL です。

ORB を使用する主なタイプのサービスは、JTS 仕様を使用する分散 Object Transaction Service 仕様のシステムです。特にレガシーシステムなどの他のシステムでは、通信にリモート Jakarta Enterprise Beans、Jakarta Enterprise Web Services、Jakarta RESTful Web Services などの他のメカニズムではなく ORB を使用することができます。

ORB 移植性 API は ORB とやりとりするメカニズムを提供します。この API は ORB への参照を取得するメソッドや、ORB からの受信接続をリッスンするモードにアプリケーションを置くメソッドを提供します。API のメソッドの一部はすべての ORB によってサポートされていません。このような場合、例外が発生します。

API は 2 つの異なるクラスによって構成されます。

  • com.arjuna.orbportability.orb
  • com.arjuna.orbportability.oa

ORB Portability API に含まれるメソッドとプロパティーの詳細は、Red Hat カスタマーポータルの JBoss EAP Javadocs バンドルを参照してください。

11.3. トランザクションの最適化

11.3.1. トランザクション最適化の概要

JBoss EAP のトランザクションマネージャー (TM) には、アプリケーションで利用できる複数の最適化機能が含まれています。

最適化機能は、特定のケースで 2 フェーズコミットプロトコルを拡張するために使用します。一般的に、TM によって、2 フェーズコミットを介して渡されるグローバルトランザクションが開始されます。ただし、これらのトランザクションを最適化する場合、特定のケースでは TM によって完全な 2 フェーズコミットを行う必要がないため、処理は速くなります。

TM により使用される別の最適化機能は、以下で詳細に説明されています。

11.3.2. 1 フェーズコミット (1PC) の LRCO 最適化

1 フェーズコミット (1PC)

トランザクションでは、2 フェーズコミットプロトコル (2PC) がより一般的に使用されますが、両フェーズに対応する必要がなかったり、対応できない場合もあります。そのような場合、1 フェーズコミット (1PC) プロトコルを使用できます。1 フェーズコミットプロトコルは、XA または非 XA リソースの 1 つがグローバルトランザクションの一部である場合に使用されます。

一般的に、準備フェースでは、第 2 フェーズが処理されるまでリソースがロックされます。1 フェーズコミットは、準備フェースが省略され、コミットのみがリソースに対して処理されることを意味します。指定されない場合は、グローバルトランザクションに参加者が 1 つだけ含まれるときに 1 フェーズコミット最適化機能が自動的に使用されます。

最終リソースコミット最適化 (LRCO: Last Resource Commit Optimization)

非 XA データソースが XA トランザクションに参加する場合は、最終リソースコミット最適化 (LRCO) と呼ばれる最適化機能が使用されます。このプロトコルにより、ほとんどのトランザクションは正常に完了しますが、一部のエラーによってトランザクションの結果の一貫性が失われることがあります。そのため、この方法は最終手段として使用してください。

非 XA リソースは準備フェーズの終了時に処理され、コミットが試行されます。コミットに成功すると、トランザクションログが書き込まれ、残りのリソースがコミットフェーズに移動します。最終リソースがコミットに失敗すると、トランザクションはロールバックされます。

ローカルの TX データソースが 1 つのみトランザクションで使用されると、LRCO が自動的に適用されます。

これまでは、LRCO メソッドを使用して非 XA リソースを XA トランザクションに追加していました。ただし、この場合は LRCO が失敗する可能性があります。LRCO メソッドを用いて非 XA リソースを XA トランザクションに追加する手順は次のとおりです。

  1. XA トランザクションを準備します。
  2. LRCO をコミットします。
  3. トランザクションログを書き込みます。
  4. XA トランザクションをコミットします。

手順 2 と手順 3 の間でクラッシュした場合、データが不整合になり、XA トランザクションをコミットできなくなることがあります。データの不整合が発生する理由は、LRCO 非 XA リソースがコミットされても、XA リソースの準備に関する情報が記録されなかったことです。リカバリーマネージャーはサーバーの起動後にリソースをロールバックします。CMR (Commit Markable Resource) ではこの制限がなくなり、非 XA リソースが確実に XA トランザクションに登録できるようになります。

注記

CMR は、特別な LRCO 最適化機能であり、データソースのみに使用する必要があります。非 XA リソースには適していません。

11.3.2.1. Commit Markable Resource (CMR)

概要

Commit Markable Resource (CMR) インターフェースを使用してリソースマネージャーへのアクセスを設定すると、非 XA データソースを XA (2PC) トランザクションに安定的に登録できます。これは、非 XA リソースを完全にリカバリー可能にする LRCO アルゴリズムの実装です。

CMR を設定するには、以下のことを行う必要があります。

  1. データベースでテーブルを作成します。
  2. データソースを接続可能にします。
  3. transactions サブシステムへの参照を追加します。
データベースでのテーブルの作成

トランザクションには CMR リソースを 1 つだけ含めることができます。以下の例と似た SQL を使用してテーブルを作成できます。

SELECT xid,actionuid FROM _tableName_ WHERE transactionManagerID IN (String[])
DELETE FROM _tableName_ WHERE xid IN (byte[[]])
INSERT INTO _tableName_ (xid, transactionManagerID, actionuid) VALUES (byte[],String,byte[])

以下は、さまざまなデータベース管理システムのテーブルを作成するための SQL 構文の例になります。

例: Sybase のテーブル作成構文

CREATE TABLE xids (xid varbinary(144), transactionManagerID varchar(64), actionuid varbinary(28))

例: Oracle のテーブル作成構文

CREATE TABLE xids (xid RAW(144), transactionManagerID varchar(64), actionuid RAW(28))
CREATE UNIQUE INDEX index_xid ON xids (xid)

例: IBM のテーブル作成構文

CREATE TABLE xids (xid VARCHAR(255) for bit data not null, transactionManagerID
varchar(64), actionuid VARCHAR(255) for bit data not null)
CREATE UNIQUE INDEX index_xid ON xids (xid)

例: SQL Server のテーブル作成構文

CREATE TABLE xids (xid varbinary(144), transactionManagerID varchar(64), actionuid varbinary(28))
CREATE UNIQUE INDEX index_xid ON xids (xid)

例: PostgreSQL のテーブル作成構文

CREATE TABLE xids (xid bytea, transactionManagerID varchar(64), actionuid bytea)
CREATE UNIQUE INDEX index_xid ON xids (xid)

例: MariaDB のテーブル作成構文

CREATE TABLE xids (xid BINARY(144), transactionManagerID varchar(64), actionuid BINARY(28))
CREATE UNIQUE INDEX index_xid ON xids (xid)

例: MySQL のテーブル作成構文

CREATE TABLE xids (xid VARCHAR(255), transactionManagerID varchar(64), actionuid VARCHAR(255))
CREATE UNIQUE INDEX index_xid ON xids (xid)

データソースを接続可能にする

デフォルトでは、CMR 機能はデータソースに対して無効になっています。有効にするには、データソースの設定を作成または変更し、connectable 属性を true に設定する必要があります。以下に、サーバーの XML 設定ファイルのデータソースセクションの例を示します。

<datasource enabled="true" jndi-name="java:jboss/datasources/ConnectableDS" pool-name="ConnectableDS" jta="true" use-java-context="true" connectable="true"/>
注記

この機能は XA データソースには適用されません。

また、以下のように管理 CLI を使用してリソースマネージャーを CMR として有効にすることもできます。

/subsystem=datasources/data-source=ConnectableDS:add(enabled="true", jndi-name="java:jboss/datasources/ConnectableDS", jta="true", use-java-context="true", connectable="true", connection-url="validConnectionURL", exception-sorter-class-name="org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLExceptionSorter", driver-name="mssql")

このコマンドは、サーバー設定ファイルの datasources セクションで以下の XML を生成します。

<datasource jta="true" jndi-name="java:jboss/datasources/ConnectableDS" pool-name="ConnectableDS" enabled="true" use-java-context="true" connectable="true">
  <connection-url>validConnectionURL</connection-url>
  <driver>mssql</driver>
  <validation>
    <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mssql.MSSQLExceptionSorter"/>
  </validation>
</datasource>
注記

データソースには、有効なドライバーが定義されている必要があります。上記の例では、mssqldriver-name として使用されますが、mssql は存在しません。詳細は、JBoss EAP 『設定ガイド』「 MySQL データソースの例 」を参照してください。

注記

データソース設定で exception-sorter-class-name パラメーターを使用します。詳細は、JBoss EAP 『設定ガイド』の 「データソース設定 の例 」を参照してください。

新しい CMR 機能を使用するために既存のリソースを更新

CMR 機能を使用するために既存のデータソースのみを更新する必要がある場合は、connectable 属性を変更します。

/subsystem=datasources/data-source=ConnectableDS:write-attribute(name=connectable,value=true)
transactions サブシステムに参照を追加

transactions サブシステムは、以下のような transactions サブシステム設定セクションへのエントリーを用いて CMR 対応のデータソースを特定します。

<subsystem xmlns="urn:jboss:domain:transactions:5.0">
    ...
    <commit-markable-resources>
        <commit-markable-resource jndi-name="java:jboss/datasources/ConnectableDS">
            <xid-location name="xids" batch-size="100" immediate-cleanup="false"/>
        </commit-markable-resource>
        ...
    </commit-markable-resources>
</subsystem>

以下のように管理 CLI を使用すると同じ結果を実現できます。

/subsystem=transactions/commit-markable-resource=java\:jboss\/datasources\/ConnectableDS/:add(batch-size=100,immediate-cleanup=false,name=xids)
注記

transactions サブシステムで CMR 参照を追加したら、サーバーを再起動する必要があります。

11.3.3. 推定中止 (presumed-abort) の最適化

トランザクションをロールバックする場合、この情報をローカルで記録し、エンリストされたすべての参加者に通知します。この通知は形式的なもので、トランザクションの結果には影響しません。すべての参加者が通知されると、このトランザクションに関する情報を削除できます。

トランザクションのステータスに対する後続の要求が行われる場合、利用可能な情報はありません。このような場合、要求側はトランザクションが中断され、ロールバックされたと見なします。推定中止 (presumed-abort) の最適化は、トランザクションがコミットの実行を決定するまで参加者に関する情報を永続化する必要がないことを意味します。 これは、トランザクションがコミットの実行を決定する前に発生した障害はトランザクションの中止であると推定されるためです。

11.3.4. 読み取り専用の最適化

参加者は、準備するよう要求されると、トランザクション中に変更したデータがないことをコーディネーターに伝えることができます。参加者が最終的にどうなってもトランザクションに影響を与えることはないため、このような参加者にトランザクションの結果について通知する必要はありません。この読み取り専用の参加者はコミットプロトコルの第 2 フェーズから省略可能です。

11.4. トランザクションの結果

11.4.1. トランザクションの結果

可能なトランザクションの結果は次の 3 つになります。

コミット
トランザクションの参加者すべてがコミットできる場合、トランザクションコーディネーターはコミットの実行を指示します。詳細は、「トランザクションのコミット」を参照してください。
ロールバック
トランザクションの参加者のいずれかがコミットできなかったり、トランザクションコーディネーターが参加者にコミットを指示できない場合は、トランザクションがロールバックされます。詳細は、「トランザクションのロールバック」を参照してください。
ヒューリスティックな結果
トランザクションの参加者の一部がコミットし、他の参加者がロールバックした場合をヒューリスティックな結果と呼びます。ヒューリスティックな結果には、人間の介入が必要になります。詳細は、「ヒューリスティックな結果」を参照してください。

11.4.2. トランザクションのコミット

トランザクションの参加者がコミットすると、新規の状態が永続化されます。新規の状態はトランザクションで作業を行った参加者により作成されます。トランザクションのメンバーがデータベースに記録を書き込む時などが最も一般的な例になります。

コミット後、トランザクションの情報はトランザクションコーディネーターから削除され、新たに書き込まれた状態が永続状態となります。

11.4.3. トランザクションのロールバック

トランザクションの参加者は、トランザクションの開始前に、状態を反映するために状態をリストアし、ロールバックを行います。ロールバック後の状態はトランザクション開始前の状態と同じになります。

11.4.4. ヒューリスティックな結果

ヒューリスティックな結果 (アトミックでない結果) は、トランザクションでの参加者の決定がトランザクションマネージャーのものとは異なる状況です。ヒューリスティックな結果が起こると、システムの整合性が保たれなくなることがあり、通常、解決に人的介入が必要になります。ヒューリスティックな結果に依存するようなコードは記述しないようにしてください。

通常、ヒューリスティックな結果は、2 フェーズコミット (2PC) プロトコルの 2 番目のフェーズで発生します。まれに、この結果が 1PC で発生することがあります。多くの場合、これは基盤のハードウェアまたは基盤のサーバーの通信サブシステムの障害によって引き起こされます。

ヒューリスティックな結果は、トランザクションマネージャーおよび完全なクラッシュリカバリーをしようした場合でも、さまざまなサブシステムまたはリソースのタイムアウトによって可能になります。何らかの形の分散合意が必要なシステムでは、グローバルな結果という点でシステムのいくつかの部分が分岐する状況が発生することがあります。

ヒューリスティックな結果には 4 種類あります。

ヒューリスティックロールバック

コミット操作はリソースをコミットできませんでしたが、すべての参加者はロールバックでき、アトミックな結果が実現されました。

ヒューリスティックコミット

参加者のすべてが一方的にコミットしたため、ロールバック操作に失敗します。たとえば、コーディネーターが正常にトランザクションを準備したにも関わらず、ログ更新の失敗などでコーディネーター側で障害が発生したため、ロールバックの実行を決定した場合などに発生します。暫定的に参加者がコミットの実行を決定する場合があります。

ヒューリスティック混合

一部の参加者がコミットし、その他の参加者はロールバックした状態です。

ヒューリスティックハザード

更新の一部の配置が不明な状態です。不明なものはすべてコミットまたはロールバックされています。

11.4.5. JBoss Transactions エラーと例外

UserTransaction のメソッドによって発生する例外に関する詳細は、UserTransaction API Javadoc を参照してください。

11.5. トランザクションライフサイクルの概要

11.5.1. トランザクションライフサイクル

Jakarta Transactions の詳細は、「Jakarta Transactions について」を参照してください。

リソースがトランザクションへの参加を要求すると、一連のイベントが開始されます。トランザクションマネージャー (TM) は、アプリケーションサーバー内に存在するプロセスであり、トランザクションを管理します。トランザクションの参加者は、トランザクションに参加するオブジェクトです。リソースは、データソース、Jakarta Messaging 接続ファクトリー、またはその他の Jakarta Connectors 接続です。

  1. アプリケーションは新しいトランザクションを開始します。

    トランザクションを開始するために、アプリケーションは Java Naming and Directory Interface から (Jakarta Enterprise Beans の場合はアノテーションから) UserTransaction クラスのインスタンスを取得します。UserTransaction インターフェースには、トップレベルのトランザクションを開始、コミット、およびロールバックするメソッドが含まれています。新規作成されたトランザクションは、そのトランザクションを呼び出すスレッドと自動的に関連付けされます。ネストされたトランザクションは Jakarta Transaction ではサポートされないため、すべてのトランザクションがトップレベルのトランザクションとなります。

    UserTransaction.begin() メソッドが呼び出されると、Jakarta Enterprise Beans がトランザクションを開始します。このトランザクションのデフォルトの動作は TransactionAttribute アノテーションまたは ejb.xml 記述子の使用によって影響を受けることがあります。この時点以降に使用されたリソースは、このトランザクションと関連付けられます。2 つ以上のリソースが登録された場合、トランザクションは XA トランザクションになり、コミット時に 2 フェーズコミットプロトコルに参加します。

    注記

    デフォルトでは、トランザクションは Jakarta Enterprise Beans のアプリケーションコンテナーによって駆動されます。これは Container Managed Transaction (CMT) と呼ばれます。トランザクションをユーザー駆動にするには、Transaction ManagementBean Managed Transaction (BMT) に変更する必要があります。BMT では、UserTransaction オブジェクトはユーザーがトランザクションを管理するために使用できます。

  2. アプリケーションが状態を変更します。

    次の手順では、アプリケーションが作業を実行し、登録されたリソースに対してのみ状態を変更します。

  3. アプリケーションはコミットまたはロールバックの実行を決定します。

    アプリケーションの状態の変更が完了すると、アプリケーションはコミットするか、またはロールバックするかを決定します。これは、適切なメソッド (UserTransaction.commit() または UserTransaction.rollback()) を呼び出します。CMT の場合、このプロセスは自動的に駆動されますが、BMT の場合は、UserTransaction のメソッドコミットまたはロールバックを明示的に呼び出す必要があります。

  4. TM がレコードからトランザクションを削除します。

    コミットあるいはロールバックが完了すると、TM はレコードをクリーンアップし、トランザクションログからトランザクションに関する情報を削除します。

障害リカバリー

リソース、トランザクションの参加者、またはアプリケーションサーバーがクラッシュするか、使用できなくなった場合は、障害が解決され、リソースが再度使用できるようになったときに Transaction Manager がリカバリーを実行します。このプロセスは自動的に実行されます。詳細は、「XA リカバリー」を参照してください。

11.6. トランザクションサブシステムの設定

transactions サブシステムでは、統計、タイムアウト値、トランザクションロギングなどのトランザクションマネージャーのオプションを設定できます。トランザクションを管理し、トランザクションの統計を表示することもできます。

詳細は、JBoss EAP 『設定ガイド』 の「トランザクション の設定 」を参照してください。

11.7. 実際のトランザクションの使用

11.7.1. トランザクション使用の概要

次の手順は、アプリケーションでトランザクションを使用する必要がある場合に役に立ちます。

11.7.2. トランザクションの制御

はじめに

この手順のリストでは、JTS API を使用するアプリケーションでトランザクションを制御するさまざまな方法を概説します。

11.7.2.1. トランザクションの開始

この手順では、新しいトランザクションの開始方法を示します。API は、Jakarta Transactions または JTS で設定された Transaction Manager ™ を実行する場合と同じです。

  1. UserTransaction のインスタンスを取得します。

    @TransactionManagement(TransactionManagementType.BEAN) アノテーションを用いると、Java Naming and Directory Interface、インジェクション、または EJB のコンテキスト EJB が Bean 管理のトランザクションを使用する場合) を使用してインスタンスを取得できます 。

    • Java Naming and Directory Interface を使用してインスタンスを取得します。

      new InitialContext().lookup("java:comp/UserTransaction")
    • インジェクションを使用してインスタンスを取得します。

      @Resource UserTransaction userTransaction;
    • EJB コンテキストを使用してインスタンスを取得します。

      • ステートレス/ステートフル Bean の場合

        @Resource SessionContext ctx;
        ctx.getUserTransaction();
      • メッセージ駆動型 Bean の場合

        @Resource MessageDrivenContext ctx;
        ctx.getUserTransaction()
  2. データソースに接続したら UserTransaction.begin() を呼び出します。

    try {
        System.out.println("\nCreating connection to database: "+url);
        stmt = conn.createStatement();  // non-tx statement
        try {
            System.out.println("Starting top-level transaction.");
            userTransaction.begin();
            stmtx = conn.createStatement(); // will be a tx-statement
            ...
        }
    }

結果

トランザクションが開始します。トランザクションをコミットまたはロールバックするまで、データソースの使用はすべてトランザクションになります。

完全な例は、「Jakarta Transactions トランザクションの例」を参照してください。

注記

EJB (CMT または BMT のいずれかと使用) の利点の 1 つは、コンテナーがトランザクション処理の内部をすべて管理することです。 そのため、ユーザーは JBoss EAP コンテナー間の XA トランザクションまたはトランザクションディストリビューションの一部であるトランザクションを処理する必要がありません。

11.7.2.1.1. ネストされたトランザクション

ネストされたトランザクションを用いると、アプリケーションは既存のトランザクションに埋め込まれるトランザクションを作成できます。このモデルでは、再帰的に複数のサブトランザクションをトランザクションに埋め込むことができます。親トランザクションをコミットまたはロールバックせずにサブトランザクションをコミットまたはロールバックできます。しかし、コミット操作の結果は、先祖のトランザクションがすべてコミットしたかどうかによって決まります。

実装固有の情報は、Narayana プロジェクトドキュメンテーションを参照してください。

ネストされたトランザクションは、JTS 仕様と使用した場合のみ利用できます。ネストされたトランザクションは JBoss EAP アプリケーションサーバーではサポートされない機能です。また、多くのデータベースベンダーがネストされたトランザクションをサポートしないため、ネストされたトランザクションをアプリケーションに追加する前にデータベースベンダーにお問い合わせください。

11.7.2.2. トランザクションのコミット

この手順では、Java Transaction を使用してトランザクションをコミットする方法を説明します。

前提条件

トランザクションは、コミットする前に開始する必要があります。トランザクションの開始方法は、「トランザクションの開始」を参照してください。

  1. UserTransactioncommit() メソッドを呼び出します。

    UserTransaction で commit() メソッドを呼び出すと、TM はトラザクションのコミットを実行します。

    @Inject
    private UserTransaction userTransaction;
    
    public void updateTable(String key, String value) {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        try {
            userTransaction.begin();
            <!-- Perform some data manipulation using entityManager -->
            ...
            // Commit the transaction
            userTransaction.commit();
        } catch (Exception ex) {
            <!-- Log message or notify Web page -->
            ...
            try {
                userTransaction.rollback();
            } catch (SystemException se) {
                throw new RuntimeException(se);
            }
            throw new RuntimeException(ex);
        } finally {
            entityManager.close();
        }
    }
  2. CMT (Container Managed Transaction) を使用する場合は、手動でコミットする必要はありません。

    Bean がコンテナー管理トランザクションを使用するよう設定すると、コンテナーはコードで設定したアノテーションに基づいてトランザクションライフサイクルを管理します。

    @PersistenceContext
    private EntityManager em;
    
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void updateTable(String key, String value)
      <!-- Perform some data manipulation using entityManager -->
      ...
    }

結果

データソースがコミットされ、トランザクションが終了します。 そうでない場合は、例外が発生します。

注記

完全な例は、「Jakarta Transactions トランザクションの例」を参照してください。

11.7.2.3. トランザクションのロールバック

この手順では、Java Transactions を使用してトランザクションをロールバックする方法を説明します。

前提条件

トランザクションは、ロールバックする前に開始する必要があります。トランザクションの開始方法は、「トランザクションの開始」を参照してください。

  1. UserTransactionrollback() メソッドを呼び出します。

    UserTransactionrollback() メソッドを呼び出す場合、TM はトランザクションをロールバックし、データを前の状態に戻そうとします。

    @Inject
    private UserTransaction userTransaction;
    
    public void updateTable(String key, String value)
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        try {
            userTransaction.begin():
            <!-- Perform some data manipulation using entityManager -->
              ...
              // Commit the transaction
            userTransaction.commit();
        } catch (Exception ex) {
            <!-- Log message or notify Web page -->
            ...
            try {
                userTransaction.rollback();
            } catch (SystemException se) {
                throw new RuntimeException(se);
            }
            throw new RuntimeException(e);
        } finally {
            entityManager.close();
        }
    }
  2. CMT (Container Managed Transaction) を使用する場合は、トランザクションを手動でロールバックする必要はありません。

    Bean がコンテナー管理トランザクションを使用するよう設定すると、コンテナーはコードで設定したアノテーションに基づいてトランザクションライフサイクルを管理します。

注記

CMT のロールバックは RuntimeException が発生すると実行されます。setRollbackOnly メソッドを明示的に呼び出してロールバックを発生させることもできます。または、 アプリケーション例外の @ApplicationException(rollback=true) を使用してロールバックできます。

結果

トランザクションは TM によりロールバックされます。

注記

完全な例は、「Jakarta Transactions トランザクションの例」を参照してください。

11.7.3. トランザクションにおけるヒューリスティックな結果の処理方法

ヒューリスティックなトランザクションの結果はよく発生するものではなく、通常は例外的な原因が存在します。ヒューリスティックという言葉は「手動」を意味し、こうした結果は通常手動で処理する必要があります。トランザクションのヒューリスティックな結果は、「ヒューリスティックな結果」を参照してください。

この手順では、Java Transactions を使用してトランザクションのヒューリスティックな結果を処理する方法を説明します。

  1. トランザクションのヒューリスティックな結果の原因は、リソースマネージャーがコミットまたはロールバックの実行を約束したにも関わらず、約束を守らなかったことにあります。原因としては、サードパーティーコンポーネント、サードパーティーコンポーネントと JBoss EAP 間の統合レイヤー、または JBoss EAP 自体の問題が考えられます。

    ヒューリスティックなエラーの最も一般的な 2 つの原因は、環境での一時的な障害と、リソースマネージャー対応時のコーディングエラーです。

  2. 通常、環境内で一時的な障害が発生した場合は、ヒューリスティックなエラーを発見する前に気づくはずです。原因としては、ネットワークの停止、ハードウェア障害、データベース障害、電源異常などが考えられます。

    ストレステストの実施中にテスト環境でヒューリスティックな結果が発生した場合は、テスト環境の脆弱性を意味します。

    警告

    JBoss EAP は、障害発生時にヒューリスティックな状態ではないトランザクションを自動的にリカバリーしますが、ヒューリスティックなトランザクションのリカバリーは実行しません。

  3. 環境に明白な障害が発生していない場合や、ヒューリスティックな結果を簡単に再現できる場合は、おそらくコーディングエラーが原因です。サードパーティーベンダーに連絡して解決策があるかどうかを確認する必要があります。

    JBoss EAP のトランザクションマネージャー自体に問題があることを疑う場合は、サポートチケットを作成する必要があります。

  4. 管理 CLI を使用して手動によるトランザクションのリカバリーを試すことができます。詳細は、JBoss EAP『 Managing Transactions on JBoss EAP 』の「 Recovering a Transaction participants」を参照してください。
  5. トランザクションの結果を手作業で解決する処理は、障害の正確な状況によって異なります。環境に合わせて以下の手順を実行します。

    1. 関係しているリソースマネージャーを特定します。
    2. トランザクションマネージャーとリソースマネージャーの状態を調べます。
    3. 関係するコンポーネントの 1 つまたは複数で、ログの消去とデータの照合を手動で強制します。
  6. テスト環境である場合や、データの整合性を気にしない場合は、トランザクションログを削除して JBoss EAP を再起動すると、ヒューリスティックな結果はなくなります。デフォルのトランザクションログの場所はスタンドアロンサーバーでは EAP_HOME/standalone/data/tx-object-store/ ディレクトリー、管理対象ドメインでは EAP_HOME/domain/servers/SERVER_NAME/data/tx-object-store/ ディレクトリーになります。管理対象ドメインの場合、 SERVER_NAME は、サーバーグループに参加している個々のサーバー名を示します。

    注記

    トラザクションログの場所は、使用中のオブジェクトストアや、object-store-relative-to および object-store-path パラメーターに設定された値にも左右されます。標準のシャドーログや Apache ActiveMQ Artemis ログなどのファイルシステムログの場合、デフォルトディレクトリーの場所が使用されますが、JDBC オブジェクトストアを使用する場合は、トランザクションログはデータベースに保存されます。

11.7.4. Jakarta Transactions Transaction エラー処理

11.7.4.1. トランザクションエラーの処理

トランザクションエラーは、多くの場合、タイミングに依存するため、解決するのが困難です。以下に、一部の一般的なエラーと、これらのエラーのトラブルシューティングに関するヒントを示します。

注記

これらのガイドラインはヒューリスティックエラーに適用されません。ヒューリスティックエラーが発生した場合は、トランザクションにおけるヒューリスティックな結果の処理方法 を参照し、Red Hat グローバルサポートサービスまでお問い合わせください。

トランザクションがタイムアウトになったが、ビジネスロジックスレッドが認識しませんでした。

多くの場合、このようなエラーは、Hibernate がレイジーロードのデータベース接続を取得できない場合に発生します。頻繁に発生する場合は、タイムアウト値を増加できます。トランザクションマネージャーの 設定に関する情報は、JBoss EAP『設定ガイド』 参照してください。

引き続き問題が解決されない場合、外部環境を調整して実行をさらに速くしたり、さらなる効率化のためにコードを再構築できることがあります。タイムアウトの問題が解消されない場合は、Red Hat グローバルサポートサービスにお問い合わせください。

トランザクションがすでにスレッドで実行されているか、NotSupportedException 例外が発生する

NotSupportedException 例外は、通常、Jakarta Transactions transaction トランザクションをネストしようとし、ネストがサポートされていないことを示します。トランザクションをネストしようとしないときは、多くの場合、スレッドプールタスクで別のトランザクションが開始されますが、トランザクションを中断または終了せずにタスクが終了します。

通常、アプリケーションはこれを自動的に処理する UserTransaction を使用します。その場合は、フレームワークに問題があることがあります。

コードで TransactionManager メソッドまたは Transaction メソッドを直接使用する場合は、トランザクションをコミットまたはロールバックするときに次の動作に注意してください。コードで TransactionManager メソッドを使用してトランザクションを制御する場合は、トランザクションをコミットまたはロールバックすると、現在のスレッドからトランザクションの関連付けが解除されます。ただし、コードで Transaction メソッドを使用する場合は、トランザクションが実行されているスレッドと関連付けられていないことがあり、スレッドプールに返す前に手動でスレッドからトランザクションの関連付けを解除する必要があります。

2 番目のローカルリソースを登録することはできません。
このエラーは、2 番目の非 XA リソースをトランザクションに登録しようとした場合に、発生します。1 つのトランザクションで複数のリソースが必要な場合、それらのリソースは XA である必要があります。

11.8. トランザクションに関するリファレンス

11.8.1. Jakarta Transactions のトランザクションの例

この例では、 Jakarta Transactions transaction トランザクションを開始、コミット、およびロールバックする方法を示します。使用している環境に合わせて接続およびデータソースパラメーターを調整し、データベースで 2 つのテストテーブルをセットアップする必要があります。

public class JDBCExample {
    public static void main (String[] args) {
        Context ctx = new InitialContext();
        // Change these two lines to suit your environment.
        DataSource ds = (DataSource)ctx.lookup("jdbc/ExampleDS");
        Connection conn = ds.getConnection("testuser", "testpwd");
        Statement stmt = null; // Non-transactional statement
        Statement stmtx = null; // Transactional statement
        Properties dbProperties = new Properties();

        // Get a UserTransaction
        UserTransaction txn = new InitialContext().lookup("java:comp/UserTransaction");

        try {
            stmt = conn.createStatement();  // non-tx statement

            // Check the database connection.
            try {
                stmt.executeUpdate("DROP TABLE test_table");
                stmt.executeUpdate("DROP TABLE test_table2");
            }
            catch (Exception e) {
                throw new RuntimeException(e);
                // assume not in database.
            }

            try {
                stmt.executeUpdate("CREATE TABLE test_table (a INTEGER,b INTEGER)");
                stmt.executeUpdate("CREATE TABLE test_table2 (a INTEGER,b INTEGER)");
            }
            catch (Exception e) {
                throw new RuntimeException(e);
            }

            try {
                System.out.println("Starting top-level transaction.");

                txn.begin();

                stmtx = conn.createStatement(); // will be a tx-statement

                // First, we try to roll back changes

                System.out.println("\nAdding entries to table 1.");

                stmtx.executeUpdate("INSERT INTO test_table (a, b) VALUES (1,2)");

                ResultSet res1 = null;

                System.out.println("\nInspecting table 1.");

                res1 = stmtx.executeQuery("SELECT * FROM test_table");

                while (res1.next()) {
                    System.out.println("Column 1: "+res1.getInt(1));
                    System.out.println("Column 2: "+res1.getInt(2));
                }
                System.out.println("\nAdding entries to table 2.");

                stmtx.executeUpdate("INSERT INTO test_table2 (a, b) VALUES (3,4)");
                res1 = stmtx.executeQuery("SELECT * FROM test_table2");

                System.out.println("\nInspecting table 2.");

                while (res1.next()) {
                    System.out.println("Column 1: "+res1.getInt(1));
                    System.out.println("Column 2: "+res1.getInt(2));
                }

                System.out.print("\nNow attempting to rollback changes.");

                txn.rollback();

                // Next, we try to commit changes
                txn.begin();
                stmtx = conn.createStatement();
                System.out.println("\nAdding entries to table 1.");
                stmtx.executeUpdate("INSERT INTO test_table (a, b) VALUES (1,2)");
                ResultSet res2 = null;

                System.out.println("\nNow checking state of table 1.");

                res2 = stmtx.executeQuery("SELECT * FROM test_table");

                while (res2.next()) {
                    System.out.println("Column 1: "+res2.getInt(1));
                    System.out.println("Column 2: "+res2.getInt(2));
                }

                System.out.println("\nNow checking state of table 2.");

                stmtx = conn.createStatement();

                res2 = stmtx.executeQuery("SELECT * FROM test_table2");

                while (res2.next()) {
                    System.out.println("Column 1: "+res2.getInt(1));
                    System.out.println("Column 2: "+res2.getInt(2));
                }

                txn.commit();
            }
            catch (Exception ex) {
                throw new RuntimeException(ex);

            }
        }
        catch (Exception sysEx) {
            sysEx.printStackTrace();
            System.exit(0);
        }
    }
}

11.8.2. トランザクション API ドキュメンテーション

トランザクション Jakarta Transactions API ドキュメンテーションは以下の場所で Javadoc として利用できます。

Red Hat Developer Studio を使用してアプリケーションを開発する場合は、API ドキュメンテーションは Help メニューに含まれています。

Red Hat logoGithubRedditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

© 2024 Red Hat, Inc.