読者です 読者をやめる 読者になる 読者になる

Java EE 7のTransactionalアノテーションを試してみる

Java EE 7からの新機能 JTA 1.2で追加されたTransactionalアノテーションを試してみた。


まずmessageというフィールドをもった単純なEntityクラスを作成して

@Entity
public class Test implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String message;

    // GetterとSetterは長いので省略
}


次にデータを追加するクラスを作成するのだけれども今まで作成していたSessionBeanはこんな感じ。

@Stateless
public class TestFacade {
    @PersistenceContext(unitName = "TESTPU")
    private EntityManager em;

    public void test() throws Exception {
        Test t = new Test();
        t.setMessage("test");
        em.persist(t);
    }
}


でも今回はこれをTransactionalを付加したCDIのクラスに修正する。

@RequestScoped
public class TestFacade {
    @PersistenceContext(unitName = "TESTPU")
    private EntityManager em;

    @Transactional
    public void test() throws Exception {
        Test t = new Test();
        t.setMessage("test");
        em.persist(t);
    }
}


TestFacadeをインジェクトしてtestメソッドを実行するともちろんデータが増える
f:id:den2sn:20130617221833p:plain


ではデータ登録後にExceptionを発生させるように修正する

@Transactional
public void test() throws Exception {
    Test t = new Test();
    t.setMessage("test");
    em.persist(t);
    throw new Exception(); //追加
}


実行するとExceptionがスローされるがチェック例外なのでやっぱりデータは追加される。
f:id:den2sn:20130617221946p:plain


ではExceptionではなくてRuntimeExceptionを発生させる。

@Transactional
public void test() throws Exception {
    Test t = new Test();
    t.setMessage("test");
    em.persist(t);
    throw new RuntimeException(); //変更
}


実行すると今度は非チェック例外なのでjavax.transaction.TransactionalExceptionがスローされて追加処理はロールバックされる。
f:id:den2sn:20130617221946p:plain


ではTransactionalアノテーションのrollbackOnにExceptionクラスを指定したうえでExceptionを発生させてみる

@Transactional(rollbackOn = Exception.class)
public void test() throws Exception {
    Test t = new Test();
    t.setMessage("test");
    em.persist(t);
    throw new Exception();
}


実行するとチェック例外であってもデータはロールバックされて追加されない。エラーはもちろんTransactionalExceptionになる。
f:id:den2sn:20130617221946p:plain


ではExceptionを継承したClassNotFoundExceptionを発生させてみる

@Transactional(rollbackOn = Exception.class)
public void test() throws Exception {
    Test t = new Test();
    t.setMessage("test");
    em.persist(t);
    throw new ClassNotFoundException();
}


実行するとバグなのか仕様なのかわからないけれど処理はロールバックされずにコミットされた。継承クラスじゃ駄目なのかな。
(バグっぽい:https://java.net/jira/browse/GLASSFISH-20533)
2015/4/26 追記:GlassFish4.1ではロールバックするように修正されていました。

f:id:den2sn:20130617222243p:plain


基本的にはSessionBeanのトランザクション制御と大きな大差は無い感じ。今後はSessionBeanはあまり使わずにこっちがメインになるかもね。