8. JTAアプリケーションの開発

8.1. プログラミング・開発ガイド

本節ではJTA(Java Transaction API)を利用したアプリケーションの作成方法について説明します。JTAはEJBにおいてBean管理のトランザクションを利用する際や、Webコンテナ上で動作するServletやJSP、あるいはアプリケーションクライアントからトランザクションを実行するために利用されます。
以下にデータベースを更新するトランザクションを実行するプログラミング例を示し、その中の各項目について説明していきます。
import javax.ejb.SessionContext;
import javax.transaction.UserTransaction;
import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.sql.Connection;
 
InitialContext ic = new InitialContext();
UserTransaction utx = (UserTransaction)ic.lookup("java:comp/UserTransaction");
DataSource ds = (DataSource)ic.lookup("DB/sample");
UserTransaction utx = ctx.getUserTransaction();
 
// 以下、トランザクション処理
utx.begin();
try {
    // 業務処理
    Connection con = ds.getConnection();
    // コネクション(con)を利用したデータベース更新をここで行なう
    con.close();
    utx.commit();
} catch (Exception e) {
    // 例外処理
    if (con != null) con.close();
    utx.rollback();
}

8.1.1. UserTransactionインスタンスの取得

ユーザアプリケーションではUserTransactionインタフェースを利用してトランザクションを実行します。そのためまずUserTransactionインスタンスを取得する必要があります。取得の方法は利用するアプリケーションによって異なります。

8.1.1.1. EJBコンテナから利用する場合

Bean管理のトランザクションを利用する際にUserTransactionインスタンスを取得します。取得方法は以下のとおりです。
// セッションBeanのsetSessionContextメソッド内で渡されたSessionContextを
// フィールド変数(sessionContext)として保持しておく
SessionContext ctx = sessionContext;
UserTransaction utx = ctx.getUserTransaction();

この場合、トランザクション開始前にJDBCコネクションを取得したり、トランザクション完了後にJDBCコネクションをクローズすることができます。

8.1.1.2. EJBコンテナ、Webコンテナ、アプリケーションクライアントから利用する場合

JNDIサーバよりUserTransactionを取得します。取得方法は以下のとおりです。
InitialContext ic = new InitialContext();
UserTransaction utx = (UserTransaction)ic.lookup("java:comp/UserTransaction");

EJBアプリケーションに限り、トランザクション開始前にJDBCコネクションを取得したり、トランザクション完了後にJDBCコネクションをクローズすることができます。

8.1.1.3. それ以外の場合

JNDIサーバよりUserTransactionを取得します。取得方法は以下のとおりです。
InitialContext ic = new InitialContext();
UserTransaction utx = (UserTransaction)ic.lookup("UserTransaction");

この場合、トランザクション開始前にJDBCコネクションを取得したり、トランザクション完了後にJDBCコネクションをクローズすることはできません。

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

トランザクションを開始します。UserTransactionインタフェースの beginメソッドをコールすることで、新規トランザクションが生成されます。サブトランザクションはサポートしておりませんので、トランザクションが既に開始されている状態でトランザクションを開始しようとすると、NotSupportExceptionが返ります。
utx.begin();

8.1.3. 業務処理の実行

トランザクション内で実行する業務処理を記載します。具体的には他のEJB Beanの呼び出しを行なったり、データベースへのアクセスを行ないます。以下は、データベースにアクセスする例です。
DataSource ds = (DataSource)ic.lookup("DB/sample");
Connection con = ds.getConnection();
// コネクション(con)を利用したデータベース更新をここで行なう
con.close();

Memo
データベースのアクセス方法の詳細については、 [ アプリケーション開発ガイド(共通) > 3. JDBCアプリケーションの開発 ] を参照してください。



8.1.4. トランザクションの終了

最後にトランザクションを終了します。UserTransactionインタフェースのcommitメソッドまたはrollbackメソッドをコールすることでトランザクションは終了します。begin()が正常終了した場合、必ずcommitかrollbackを呼び出す必要があります。
次のトランザクションを開始する場合、再びbeginメソッドを呼び出してください。
try {
    // 業務処理
    utx.commit();
} catch (Exception e) {
    // 例外処理
    utx.rollback();
}
トランザクションの基本的な流れについては以上です。以下ではその他のUserTransactionインタフェースのメソッドについて説明します。

8.1.5. トランザクションタイムアウトの設定

トランザクションのタイムアウト時間を設定するには、UserTransactionインタフェースのsetTransactionTimeoutメソッドをコールします。トランザクションの処理が無限ループに入ってしまった場合でも、このメソッドを利用することで、指定秒数経過後にロールバック処理が自動的に実行されます。
setTransactionTimeoutメソッドはトランザクションを開始するbeginメソッドの前にコールします。再度このメソッドを呼び出すまで以後のトランザクションはこのタイムアウト時間でロールバックするようになります。
utx.setTransactionTimeout(30);
utx.begin();
try {
    // 業務処理
    // 30秒以内に業務処理が終わらない場合自動的にロールバックする

8.1.6. ロールバックのマーク

トランザクション中に障害があったときなどに、トランザクションが最終的には必ずロールバックされるようにしたい場合があります。このときには、UserTransactionインタフェースのsetRollbackOnlyメソッドをコールします。
業務処理で例外が発生した場合にrollbackメソッドをコールする代わりに以下のようにすることもできます。
try {
    // 業務処理
} catch (Exception e) {
    // 例外処理
    utx.setRollbackOnly();
}
utx.commit();

8.1.7. トランザクション状態の取得

トランザクションの状態を取得するには、UserTransactionインタフェースのgetStatusメソッドをコールします。
int status = utx.getStatus();
返却される値とその意味は次の通りです。
表8.1.7-1
状態(値) 意味
STATUS_ACTIVE(0) トランザクション開始後のアクティブな状態
STATUS_COMMITTED(3) コミットが完了した状態
STATUS_COMMITTING(8) トランザクションのコミット処理中
STATUS_MARKED_ROLLBACK(1) ロールバック用にマークされた状態 (setRollbackOnly()の結果として)
STATUS_NO_TRANSACTION(6) トランザクションが開始されていない状態
STATUS_PREPARED(2) プリペアが完了した状態
STATUS_PREPARING(7) プリペアの処理中
STATUS_ROLLEDBACK(4) トランザクションの結果がロールバックと決定された状態
STATUS_ROLLING_BACK(9) ロールバック処理中
STATUS_UNKNOWN(5) トランザクションの結果が不明な状態