MyBatisのスコープとライフサイクル

備忘録。

スコープとライフサイクル
これまでに説明した様々なクラスに適したスコープや、そのライフサイクルについて理解しておくことは大変重要です。 誤って使用すると、深刻な整合性の問題の原因となります。

SqlSessionFactoryBuilder

このクラスは、インスタンス化し、使用し、破棄することができます。 一旦 SqlSessionFactory を生成してしまえば、このクラスを残しておく理由はありません。 したがって、このクラスのスコープとして最適なのはメソッドスコープ(つまり、ローカルメソッド変数)です。 SqlSessionFactoryBuilder を再利用して複数の SqlSessionFactory を生成することも可能ですが、XML をパースするためのリソースが他の重要なものを圧迫しないように、このクラスを保持して使いまわさない方が得策です。

SqlSessionFactory

生成した SqlSessionFactory は、あなたのアプリケーション実行中はそのまま残しておくべきです。 生成した SqlSessionFactory を破棄したり、再度生成する理由はないはずです。 SqlSessionFactory を再生成しない、というのは所謂ベストプラクティスで、これを行なっていたら「何かおかしいぞ」と考えるべきです。 したがって、SqlSessionFactory に最適なのはアプリケーションスコープ、ということになります。 これを実現する方法はいくつもあります。 最も簡単なのはシングルトンパターンまたはスタティックシングルトンパターンを使う方法です。

SqlSession

各スレッドは、独立した SqlSession のインスタンスを使うべきです。 SqlSession のインスタンスは共有されることを前提としていないため、スレッドセーフではありません。 当然、最適なスコープはメソッドスコープになります。 SqlSession のインスタンスへの参照を static なフィールドや、インスタンスフィールドにも格納してはいけません。 Servlet フレームワークの HttpSession のようなマネージドスコープに SqlSession への参照を保持するのもダメです。 もし何らかの Web フレームワークを使っているのであれば、SqlSession のスコープが HTTP リクエストと同調するようにしておくべきです。 つまり、HTTP リクエストを受け取ったら SqlSession をオープンし、レスポンスを返すときにクローズすれば良いのです。 セッションをクローズすることはとても重要です。 間違いがないよう、常に finally ブロックの中でセッションをクローズするようにした方が良いでしょう。 SqlSession を確実にクローズするための一般的なパターンは下記のようなものです。

SqlSession session = sqlSessionFactory.openSession();
try {
  // do work
} finally {
  session.close();
}

常にこのパターンに従っておけば、すべてのデータベースリソースを確実にクローズすることができます。

Mapper インスタンス

Mapper は、Mapped Statement をバインドするためのインターフェイスです。 Mapper インターフェイスインスタンスは SqlSession から取得されます。 したがって、Mapper インスタンスの理論上の最長のスコープは、インスタンス取得元の SqlSession と同じということになります。 ですが、Mapper インスタンスに最適なスコープはメソッドスコープです。 つまり、Mapper インスタンスを利用するメソッドの中で取得・破棄するということです。 Mapper インスタンスを明示的にクローズする必要はありません。 リクエスト処理が完了するまで残しておいても問題ありませんが、SqlSession 同様、このレベルで余分なリソースを大量に扱うと、すぐに手に負えない状況になってしまうでしょう。 単純化のため、Mapper はメソッドスコープの中で使うようにしてください。 このプラクティスを実践したのが次のサンプルになります。

SqlSession session = sqlSessionFactory.openSession();
try {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  // do work
} finally {
  session.close();
}
http://mybatis.github.io/mybatis-3/ja/getting-started.html

結論、SpringまたはGuiceでDIフレームワーク連携しましょう。
ただ怖いのでスコープは一応覚えとく。