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

using multiple databases with Spring iBatis

java spring ibatis

Spring経由でiBatisを使いつつ、複数のデータベースを利用しようと思ったら結構ハマったのでまとめておきます。


やりたいこと

  • database1にはpersonというtableがあって、database2にはprojectというtableがあり、それぞれにアクセスしたい。


解決方法の概要

  • database1, 2のそれぞれに対応するdataSourceを定義(dataSource1, dataSource2)
  • dataSource1,2を用いるsqlMapClient(sqlMapClient1,2)とtransactionManager(transactionManager1,2)をそれぞれ定義
  • sqlMapClient1,2内のconfigLocationは別ファイルにしておき(sqlmap-config-a.xml, sqlmap-config-b.xml)それぞれperson, projectテーブルに関するマッピングを定義
  • SqlMapClientDaoSupportを継承しているDaoで、setSqlMapClient()する際に適切なsqlMapClientが利用されるようにする。
    • たとえばアノテーションを用いてAutowireしているのであれば以下のような感じ
  @Autowired
  @Qualifier("sqlMapClient1")
  public void injectSqlMapClient(SqlMapClient sqlMapClient) {
    setSqlMapClient(sqlMapClient);
  }
    • これがかなり重要で、Spring, iBatisのバージョンが新しければそれっぽいエラーがでてくれるが、古めの場合は不適切なsqlMapClientがセットされるだけで進んでしまうので以下のようなエラーで悩むことになる
There is no statement named XXXXX in this SqlMap.
    • あとUnit testでAbstractTransactionalJUnit4SpringContextTestsを使っている場合、dataSourceとかtransactionManagerとかが期待通りにセットされないので、以下のように指定する必要があるみたい
@TransactionConfiguration(transactionManager = "transactionManager1")
public class TestSqlMapPersonDaoImpl extends AbstractTransactionalJUnit4SpringContextTests {
       :
  @Autowired
  @Qualifier("dataSource1")
  @Override
  public void setDataSource(DataSource dataSource) {
    super.setDataSource(dataSource);
  }

で、その辺を適当にまとめてサンプルっぽいものをおいておきました。
https://github.com/komamitsu/Spring-MVC-sample-using-iBatis

それにしても最近Springもまぁそんなに悪くないかなぁ、という感じになりつつありますね。分からないものだ。