ぶろぐ

日記です

Singletonが少しわかったので書いとく


Hibernateを使うときに、SessionFactoryをSingletonにする方法。
せっかくサンプル書いたので載せとく、これ実行して確信が持てた。
ポイントは

  • extendsはメモリの延長、親のインスタンスは一つ
    • 同じ親を継承した、別々の子クラスの親クラスが持つ属性のインスタンスは一つということ
    • 親が子供がー!先代の能力を受け継ぐー!とか言っていたら気づきにくい(かも)extends=メモリの延長
  • singletonにするフィールドは、privateでstaticにする
  • singletonにするターゲットのインスタンスは、SessionFactory
    • sessionはdaoのメソッドごとに開いて閉じる(はず)

コードはWEB+DB vol.18を参考にしました。
WEB+DBの総集編のおかげで色々とわかってきた。
平成16年、自分が16歳のときなのか。その時代はJava大ブームだったのかな…
Javaの記事が多い。お仕事で使うからかなり参考になる。
「オレは平成23年を生きたプログラマなんだ!」といいたければ、node.jsやるとかherokuやるとかやったほうがいいのかもしれないけど、まぁ別にいいや。この先どうなっていくのか見守るだけでも楽しす。
うん、電子書籍読む用にiPad欲しすぎる…

前提(やりたい事とか)

HibernateのSessionオブジェクトを生成する「SessionFactoryオブジェクト」
こいつは1アプリケーションで一つのインスタンスだけで良い。
多分複数あると困る(多分)
あと、SessionFactoryはスレッドセーフ。みんなかかってこぃ。
こいつから生成されたSessionオブジェクトを介して、データベースのやり取りを行う。SessionがDBへのリソースハンドラ的な。
使い終わったら開放しないといけないので、無くさないようにしっかり握ろうハンドル。

親クラス

package example;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class OyaDao {

       /** セッションファクトリ */
       private static SessionFactory sessionFactory = null;

       /**
        * セッションファクトリの取得。シングルトンでやってる。
        */
       static synchronized SessionFactory getSessionFactory() {

               if (sessionFactory == null) {
                       Configuration cfg = new Configuration().configure();
                       sessionFactory = cfg.buildSessionFactory();

                       System.out.println("sessionFactory生成");

               } else {
                       System.out.println("sessionFactory使いまわし");
               }

               return sessionFactory;
       }

       /**
        * セッションを取得します。
        */
       public Session getSession() {
               SessionFactory sf = getSessionFactory();
               return sf.openSession();
       }

}

子クラス1

package example;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;

import beans.Bean;

public class Ko1Dao extends OyaDao {

       public void find() {

               Session session = getSession();
               Criteria criteria = session.createCriteria(Bean.class);

               List<Bean> benas = criteria.list();

               for (Bean bean : benas) {
                       System.out.println(bean.getIsbn());
               }

       }

}

子クラス2(全く一緒だけど一応クラス分ける…)

package example;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;

import beans.Bean;

public class Ko2Dao extends OyaDao {

       public void find() {

               Session session = getSession();
               Criteria criteria = session.createCriteria(Bean.class);

               List<Bean> benas = criteria.list();

               for (Bean bean : benas) {
                       System.out.println(bean.getIsbn());
               }

       }
}

メインのクラス

package example;

public class TestSingletone {

       public static void main(String[] args) {

               Ko1Dao dao1 = new Ko1Dao();
               dao1.find();
               // SessionFactory生成、と表示される

               Ko2Dao dao2 = new Ko2Dao();
               dao2.find();
               // SessionFactory使いまわし、と表示される

       }
}

気づき

Ko1DaoとKo2Dao、別々のクラスをインスタンスしているにも関わらずSessionFactoryは一つ。
OyaDaoを継承せずに、SessionFactoryをそれぞれの子DAOで持っている場合は、こうならない(いや、当たり前だけども)
SessionFactoryはアプリケーション全体で単一のインスタンスにしたいため、SingletoneにしてFactoryクラスは一箇所にまとめる、ということが必要だとわかった一日でした。
Hibernateを使うときの不安要素が一つ消えた。
これが一番いい方法なのかどうかは知らないけど、現状これで行こう。

教訓

extends = メモリの延長(拡張)
親の性質を引き継ぐだけじゃない。親のメモリ領域を利用してその上に乗っかる。

参考サイト

@IT:いまから始めるJava 第4回
http://www.atmarkit.co.jp/fjava/rensai2/javaent04/javaent04.html