SAStrutsを勉強してみる (9) - UserTransaction -
SAStrutsっていうかS2JDBCな件だとは思うのですが、それはおいといて。トランザクションを自動化せずに手動によるトランザクションを利用したい場合のメモ
UserService.java
package sample.service;
import javax.annotation.Resource;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import org.seasar.extension.jdbc.service.S2AbstractService;
import org.seasar.extension.jdbc.where.SimpleWhere;
import sample.entity.User;
import sample.util.SampleUtil;
public class UserService extends S2AbstractService<User> {
@Resource
private UserTransaction tx;
public User getUser(String username, String password) {
if (username == null) {
throw new IllegalArgumentException("required username");
}
if (password == null) {
throw new IllegalArgumentException("required password");
}
SimpleWhere where = new SimpleWhere();
where.eq("username", username);
where.eq("password", SampleUtil.toSHA1(password.getBytes()));
return select().where(where).getSingleResult();
}
@TransactionAttribute(TransactionAttributeType.NEVER)
public void createUser(User user) {
if (user == null) {
throw new IllegalArgumentException("required user");
}
try {
tx.begin();
insert(user);
} catch (Exception e) {
try {
tx.setRollbackOnly();
} catch (IllegalStateException e1) {
e1.printStackTrace();
} catch (SystemException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
try {
if (tx.getStatus() == Status.STATUS_ACTIVE) {
tx.commit();
} else {
tx.rollback();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
手動トランザクションしたいメソッドに@TransactionAttributeでNEVERにする(もしくはNOT_SUPPORTED?)。でメソッドで例外キャッチしたらUserTransaction.setRollbackOnlyを行う事でUserTransaction.getStatusがSTATUS_MARKED_ROLLBACK(値は1)になる。あとはfinally区において、現状のトランザクションステータスによりコミットするかロールバックするかとか
っていう感じで自動トランザクションしちゃいけないケースの場合のUserTransactionの使い方はこんな感じかなと
でこれテストする場合どうなるのって所
UserServiceTestCase.java
import org.junit.Test;
import org.junit.runner.RunWith;
import org.seasar.framework.unit.Seasar2;
import org.seasar.framework.unit.annotation.TxBehavior;
import org.seasar.framework.unit.annotation.TxBehaviorType;
import sample.entity.User;
import sample.service.UserService;
@RunWith(Seasar2.class)
public class UserServiceTestCase {
UserService service;
@Test
@TxBehavior(TxBehaviorType.NONE)
public void createUserTest1() {
User user = new User();
user.userName = "test1";
user.password = "test1";
service.createUser(user);
}
@Test(expected = IllegalArgumentException.class)
@TxBehavior(TxBehaviorType.NONE)
public void createUserTest2() {
service.createUser(null);
}
}
な感じ。ちょっと気になったのはTxBehaviorしなきゃいけないケースに関してなんだけど、TransactionAttributeのNEVERとNOT_SUPPORTEDの違いとしては http://kokuzawa.blogspot.jp/2011/02/ejb31bean.html が参考になった
なので今回テストトランザクションをNONEにしないとService側のトランザクションを行う際に既にテストトランザクションが開始されているので、そこでエラーになるみたいな感じなのかなと。NOT_SUPPORTEDだと既存するトランザクションを停止させてからトランザクション処理を開始する模様なのでテスト側でTxBehaviorをしなくてもテストトランザクションはメソッド実行された段階で停止するのかなと