QUERYのカスタマイズ

マニュアル(http://homepage3.nifty.com/seasar/s2dao.html)を見て自分で試してみたメモ。
http://muimi.com/j/aop/seasar/s2dao/ のつづき。
Seasarのことは はてな に書いた方が間違いも減るかなということで。


SELECT SQLをカスタマイズするにはいくつかの方法がある。
シンプルな一致(=)条件での検索には、ARGSアノテーションを使う。
ARGSアノテーションは「メソッド名_ARGS」で定義する。

public static final String findByTitle_ARGS = "title";
public List findByTitle(String title);


発効されるSQLは以下のようになる(メソッド引数に"あああ"を渡した場合)。

SELECT CD.content, CD.id, CD.title FROM CD WHERE  CD.title = 'あああ'


もうちょっといろいろ書きたいときは、QUERYアノテーションを使う。
QUERYアノテーションは「メソッド名_QUERY」で定義する。

public static final String findByTitle_QUERY = "title = ?";	
public List findByTitle(String title);


発効されるSQLは上と同じ。
QUERYアノテーションは、WHERE句の後を記述すると、WHEREまでを自動的に作成してくれる。
SELECTから全部書くのもアリである。
SELECTから全部書くパターンは、集約関数やもうちょっと複雑なSQLを書くときに使うと思われる。

public static final String findByTitle_QUERY = "select * from cd where title = ?";	
public List findByTitle(String title);


SQLが長く複雑になる場合や、ソースにいろいろ書くのが嫌いな人は、SQL部分を外出しできる。
Dao名_メソッド名.sqlというファイルを作成し、そこにSQLを記述する。

dao/
  CdDao.java
  CdDao_findByTitle.sql


外出しSQLの場合は、WHERE以降でなく、SELECTから全部書く。
SELECTでなく、更新系のSQLをカスタマイズする場合も外出しSQLを使う。

QUERYのカスタマイズ2(バインド変数)

SQL中に?を書きたくない場合はバインド変数を利用する。

public static final String findByTitle_ARGS = "prmtitle";
public static final String findByTitle_QUERY = "select * from cd where title = /*prmtitle*/";
public List findByTitle(String title);


このメソッドを実行すると、
発効されるSQLは以下のようになる(引数に'あああ'と渡した場合)。

select * from cd where title = 'あああ'


バインド変数は、ARGSアノテーションで指定した名前(あるいはBEANのプロパティー)をSQL中で"/*名前*/"という風に指定できる。上の例は、ARGSアノテーションで指定した名前prmtitleをSQL文中で置き換えている。



EL式みたいな感じでJavaBeansにアクセスすることも可能。

public static final String findByCriteria_ARGS = "criteria";
public static final String findByCriteria_QUERY = "title = /*criteria.title*/";
public List findByCriteria(Criteria criteria);

この場合、Criteriaクラスのtitleプロパティーの値(getTitle()の返り値)が代入される。

トランザクション

トランザクション制御は、S2Txを利用する
http://homepage3.nifty.com/seasar/tx.html
(S2DAOからはじめたので、しばらくトランザクションのかけかたが不明だった。。。)。


トランザクションをかけたいクラスの例

public class TransSample {

    public void doSomeUpdate(){
        S2Container container = S2ContainerFactory.create("dao/test.dicon");
        CdDao dao = (CdDao)container.getComponent(CdDao.class);
        //...いろいろ更新
    }
}


diconファイルの例


    j2ee.requiredTx

この場合、pointcut(メソッド)の指定は必要な模様(自動的にメソッド全部にはならない)。
このメソッドを実行すると次のようなログが出る。

DEBUG 2004-10-14 22:28:10,481 [main] トランザクションを開始しました
//...いろいろ
DEBUG 2004-10-14 22:28:10,891 [main] トランザクションをコミットしました

普通にメソッドが終了すると、トランザクションがコミットされる。
途中で例外が投げられると、ロールバックされる。
いやな例外を消したいときは例外を処理するaspectをかけるといいらしい。
http://seasarproject.g.hatena.ne.jp/match8/20040902

AUTO INCREMENT

DBスキーマのプライマリキーなどが、AUTO INCREMENTの場合、
どうやってINSERTするのかなぁ?
と、外出しSQLとバインド変数を使ってできるみたい。


CdDao_insert.sql

insert into cd(title,content) 
values( /*cd.title*/,/*cd.content*/ )


で、CdDao#insert()を呼ぶときidは入れないようにすると

Cd cd = new Cd();
//cd.setId(1);
cd.setTitle("ほげほげ");
cd.setContent("あははは");
dao.insert(cd);


発効されるSQLは以下のようになる。

insert into cd(title,content) 
values( 'ほげほげ','あははは' )


ただ、INSERTされた行のAUTO INCREMENT行の値が何になったかは不明
Statement#getGeneratedKeys()にあたるものはあるのだろうか?
(別にいらないか)



S2DAO、だいぶん、いいもののような気がしてきた。
うだうだXML設定ファイルとわらわら作成されるクラス群が不要なのが気持ちいいのと
実装クラスが裏側で作られるのが若干気持ち悪いの半分です。