HibernateのSession管理について

久しぶりの投稿です。
Hibernate+spring frameworkと付き合って結構経ちますが、未だに混乱するので自分のための備忘録メモです。

HibernateのSessionとは

本から引用すると、「Sessionとは、永続化サービスの提供を行うもの。DBから取得したオブジェクトを保持し、状態管理を行うもの」です。
永続化サービスでは、「永続化コンテキスト*1に対する変更がDBに反映」されます。

HibernateのSession管理

セッションを取得・操作する方法はトランザクション管理方式によって異なります。
本に書いてある方法などをまとめます。

宣言的トランザクションを利用しているとき

宣言的トランザクション*2を利用しているときは、org.hibernate.SessionFactory.getCurrentSession()->セッション操作->flushのみでOKです。SessionのクローズやオープンはHibernateが行なってくれます。

session = sessionFactory.getCurrentSession();
//ここにセッション操作のコードを記述
session.flush();
プログラム内でトランザクション管理を行うとき

プログラム内でトランザクション管理を行うときには、セションのオープン、開始、操作、クローズを全てメソッド内に書かなければなりません。

session = sessionFactory.openSession();
session.beginTransaction();
//ここにセッション操作のコードを記述
session.getTransaction().commit();
session.close();
Spring frameworkを使ったHibernateのセッション管理

SpringのHibernateTemplateを使えば、Hibernateのセッション管理が楽ちんになります。
HibernateTemplateはhibernateのSession操作をラップしたメソッドを提供しており、Sessionのcloseとflushを自動でやってくれます。

ちなみに:HibernateTemplateで提供していないSession操作を行いたいとき

HibernateTemplateでhibernateが提供する全てのSession操作ができるわけではありません。できないこともあります。例えば、setMaxResults()などはHibernateTemplateでは提供していないメソッドです。こんなときは、Sessionに対して直接操作を行いたい。
このようなときは、HibernateCallbackを利用します。(参考:SpringのHibernateTemplateに定義されていない処理を実装する方法

これを使うことで、HibernateTemplateにセッションのオープン/クローズなどの基本的操作を任せたまま、Session操作を行うことができます。

public List<Integer> Test(final param1) {
		HibernateCallback callback = new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				List<Integer> results = session
					.createQuery("SELECT ...")
					.setParameter("param1", param1)
					.setMaxResults(1)
					.list();
				if(!results.isEmpty())
					return results;
				return null;
			}
		};
		return super.getHibernateTemplate().execute(callback);
	}

ちなみにHibernateCallbackではなくHibernateTemplate.getSessionFactory.getCurrentSession()で、現在のSessionが取得でき、直接セッション操作を行うことができます。
しかし、あまりお勧めできません。もしgetCurrentSessionを使うと、セッションのオープン/クローズなどは明示的に書かなくてはなくなり、コードの混乱を招きます。HibernateTemplateを使うと決めたら、Sessionの基本的操作は全てそこに任せるべきです。callbackを使う方法が正攻法だと思います。

*1:永続化コンテキストとは、要は複数のインスタンスのまとまりのことを指しているようです。"A persistence context is a set of entity instances..." ドキュメントを参考

*2:Springの設定ファイルで予め「あるメソッドを呼び出したときにトランザクションをかける」と宣言する方法