Spring MVC で複数データソースを扱った場合の挙動を調べてみた
Spring MVC で扱うデータソースが2つある時、片方だけトランザクションを張った場合にもう片方の更新が反映されない、という問題に直面したので色々試してみた。Spring 初心者すぎて辛い。
環境
Spring 3.2.4
元々のソース
例えば user と groupというテーブルがあり、それぞれに対して更新する処理を書いていた。
#!java
@Service
public class HogeService {
@Transactional
public void update() {
userService.update();
groupService.update();
}
}
ここで、user と group とでDBを分けることになり、DataSource と TransactionManager を複数に分けた際、デフォルトの user は更新されるが group の更新がされなくなった。この挙動自体はまぁ当然。
(1) groupService 側にも @Transactional を指定してみる
これで両方トランザクションが張られて正常に動作した。
#!java
@Service
public class GroupService {
@Transactional(“group")
public void update() {
// update...
}
}
(2) afterCommit を利用してみる
今回は group 側にトランザクションを張らなくても良いケースだったので、試しに TransactionSynchronizationAdapter#afterCommit を利用してみた。
#!java
@Service
public class HogeService {
@Transactional
public void update() {
userService.update();
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
groupService.update();
}
}
);
}
}
これでうまくいくかと思ったが、group への更新は反映されなかった。何かイメージと違う。afterCommit の後に何か処理が走っているのか。
(3) user、group への更新処理をメソッド毎分ける
StackOverflow とか Spring 関連の記事を見ていると、結局これに落ち着きそうな感じ。もちろん想定通りに動作する。
#!java
@Service
public class HogeService {
@Transactional
public void updateUser() {
userService.update();
}
@Transactional(“group")
public void updateGroup() {
groupService.update();
}
}
時間も無く、結局うまいやり方が見つからないので、(3) の実装で一旦落ち着いた。