Dropwizardでjdbiを使う場合、以下を気にする必要があります。
- トランザクション境界をどうするか
- dao一つ一つが別のトランザクション
Resourceにトランザクション境界を作る
まずは、トランザクション境界をResourceクラスにします。
daoで org.skife.jdbi.v2.sqlobject.mixins.Transactional
を継承します。
public interface PersonJdbiRepository extends Transactional<PersonJdbiRepository> {
@SqlBatch("insert into people (fullName, jobTitle) values (:fullName, :jobTitle)")
void createMany(@BindBean Iterator<Person> iterator);
・・・
次にResourceクラスで、inTransaction
メソッドを利用します。@org.skife.jdbi.v2.sqlobject.Transactionを利用しても駄目です。
引数の Transaction
実装内で例外が起きるとrollbackされるようになります。
private final PersonJdbiRepository repository;
@POST
public List<Person> createBatch() {
repository.inTransaction(new Transaction<Void, PersonJdbiRepository>() {
@Override
public Void inTransaction(PersonJdbiRepository transactional, TransactionStatus status) throws Exception {
List<Person> people = new ArrayList<Person>();
people.add(new Person("ko2ic", "batch1"));
people.add(new Person("ko2ic", "batch2"));
repository.createMany(people.iterator());
return null;
}
});
return listPeople();
}
複数Dao対応
次は、二つのDao間で一つのトランザクションにしたい場合の対処です。
これは特殊な(微妙な)処理をしなければなりません。
一方のDaoにもう一つのDaoを取得するメソッドを追加し、そのメソッドに @CreateSqlObject
アノテーションを付けます。
そして、両方を呼び出すメソッドを作ります。
文章にしてもよくわからないと思うのでコードを見て下さい。
public abstract class PersonJdbiRepository implements Transactional<PersonJdbiRepository> {
@SqlBatch("insert into people (fullName, jobTitle) values (:fullName, :jobTitle)")
public abstract void createMany(@BindBean Iterator<Person> iterator);
@CreateSqlObject
public abstract TempJdbiRepository createTempJdbiRepository();
public int createWithTemp(Iterator<Person> iterator) {
createMany(iterator);
TempJdbiRepository repository = createTempJdbiRepository();
repository.create();
// throw new IllegalArgumentException();
return repository.count();
}
}
createWithTemp()
メソッドの実装が必要なので、abstract classにしています。java8のdefault実装ではできませんでした。
createWithTemp()
メソッドに @org.skife.jdbi.v2.sqlobject.Transaction
を書くとこのメソッドがトランザクション境界になります。
Resourceクラスをトランザクション境界にしたい場合は、上記「Resourceにトランザクション境界を作る」と同様です。
下の実装は、上記内で呼ばれているもう一方のDaoです。
public interface TempJdbiRepository {
@SqlQuery("select count(id) from temp")
int count();
@SqlUpdate("insert into temp (fullName) values ('fullName')")
void create();
}