EJB 3.0(Public Draft)入門記 Simplified API Chapter 10 その2 TransactionManagement
地震長かった...。入門記どころじゃないんですけどTransactionManagementアノテーションです。
TransactionManagementアノテーションはセッションBeanやメッセージ駆動型Beanのトランザクション境界のタイプを指定するそうです。タイプにはコンテナ管理とBean管理の2種類があって、セッションBeanやメッセージ駆動型BeanにTransactionManagementアノテーションが指定されていない場合、そのBeanはコンテナ管理のトランザクション境界をもつとみなされます、とあります。
defaultはコンテナ管理ということで、いままで動かしてきたセッションBeanやメッセージ駆動型Beanはどれも自動でトランザクションに入っていたんですね。
TransactionManagementアノテーションとTransactionManagementのタイプの定義を写してみます(写経?)。
@Target(TYPE) @Retention(RUNTIME) public @interface TransactionManagement { TransactionManagementType value() default TransactionManagementType.CONTAINER; }
public enum TransactionManagementType { CONTAINER, BEAN }
実験コーナー〜。Bean管理のトランザクションを使って、SQLの更新がコミットされているかどうか見てみたいと思います。。まずJBossにくっついているHSQLDBにテーブルをつくります。JBossの管理コンソールからHSQLDBのGUIツールを動かすにはhsqldb-ds.xmlの設定を変える必要みたい?。hsqldb-ds.xmlの設定についてはhttp://cnd.daitec.co.jp/openSo/documents/jboss/GettingStartedV4/dukesbank.htmlを参考にさせてもらいました。
CREATE TABLE EMP ( EMPNO NUMERIC(4) NOT NULL PRIMARY KEY, ENAME VARCHAR(10) )
DAOを作ります。
DAOのビジネスインタフェース
public interface EmployeeDao { void insert(int no, String name); }
DAOのBeanクラス:たんにinsertをしたいだけです。
@Stateless public class EmployeeDaoBean implements EmployeeDao { @Resource(name = "DefaultDS") private DataSource dataSource; public void insert(int no, String name) { Connection con = null; try { con = dataSource.getConnection(); PreparedStatement ps = con .prepareStatement("INSERT INTO emp VALUES(?, ?)"); ps.setInt(1, no); ps.setString(2, name); ps.executeUpdate(); } catch (SQLException e) { throw new RuntimeException(e); } finally { try { con.close(); } catch (SQLException e) { } } } }
Logicを作ります。
Logicのビジネスインタフェース
public interface EmployeeLogic { void insert(int no, String name); }
LogicのBeanクラス:TransactionManagementアノテーションつかってTransactionManagementTypeにBEANを指定してます。UserTransactionを使ってBean内でトランザクションの開始とコミットを行います。
@Stateless @Remote(EmployeeLogic.class) @TransactionManagement(TransactionManagementType.BEAN) public class EmployeeLogicBean implements EmployeeLogic { @EJB private EmployeeDao dao; @Resource private UserTransaction tx; public void insert(int no, String name) { try { tx.begin(); dao.insert(no, name); tx.commit(); } catch (Exception e) { throw new RuntimeException(e); } } }
クライアント:Logicのビジネスインタフェースに値を渡してます。
public class EmployeeClient { public static void main(String[] args) throws Exception { InitialContext ctx = new InitialContext(); EmployeeLogic logic = (EmployeeLogic)ctx.lookup(EmployeeLogic.class.getName()); logic.insert(1001, "ゴン"); } }
デプロイしてクライアントを実行し、HSQLDBのGUIでEMPテーブルを見てみるとデータが追加されていることがわかりました。
今回は無理やりBean管理のトランザクションを使ってみました。コンテナ管理を使った場合、LogicのBeanクラスはこんな感じになると思います。
@Stateless @Remote(EmployeeLogic.class) public class EmployeeLogicBean implements EmployeeLogic { @EJB private EmployeeDao dao; public void insert(int no, String name) { dao.insert(no, name); } }
コンテナ管理では当然UserTransactionを使う必要はないですが、UserTransactionのDIの記述を残したままデプロイしたらJBossに怒られて「it is illegal to inject UserTransaction into a CMT bean」とか言われました。