S2JDBC を使ってみる

DBFlute も結構良さそうだったのだが、Seasar における DB 処理の本命的な印象のある S2JDBC を試してみる事にする。.NET の LINQ にも似てるし、今後はこういうスタイルが主流になるのかも。

各種 dicon ファイルの準備

手動で S2JDBC を使える状態にするために、以下のような dicon ファイルをクラスパスが通っているディレクトリにコピーする。

  • seasar2/resources から
    • convention.dicon
    • creator.dicon
    • customizer.dicon
    • jdbc.dicon
    • log4j.dicon
  • s2-tiger/resources から
  • dolteng で作ったアプリやどこかのサンプルの中から
    • s2container.dicon
    • env.txt
app.dicon の作成

app.dicon ファイルを次のような内容で作成。

<components>
  <include path="convention.dicon"/>
  <include path="aop.dicon"/>
  <include path="s2jdbc.dicon"/>
</components>
convention.dicon の編集

convention.dicon ファイル内の addRootPackageName の値に作成するアプリケーションのルートパッケージ名を設定。

<components>
  <component class="org.seasar.framework.convention.impl.NamingConventionImpl">
    <initMethod name="addRootPackageName">
      <arg>"woz"</arg>
      </initMethod>
  </component>
  <component class="org.seasar.framework.convention.impl.PersistenceConventionImpl"/>
</components>
DB関連 dicon ファイルの編集

s2jdbc.dicon の dialect の設定を使用する DB に合わせて変更。

<!-- H2 を使う場合 -->
<components>
  <include path="jdbc.dicon"/>
  <include path="s2jdbc-internal.dicon"/>
  <component name="jdbcManager" class="org.seasar.extension.jdbc.manager.JdbcManagerImpl">
    <property name="maxRows">0</property>
    <property name="fetchSize">0</property>
    <property name="queryTimeout">0</property>
    <property name="dialect">h2Dialect</property>
  </component>
</components>

jdbc.dicon の JDBC ドライバーの設定を使用する DB に合わせて変更。

<!-- H2 を使う場合 -->
<components>
  ・・・
  <component name="xaDataSource"
      class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
    <property name="driverClassName">"org.h2.Driver"</property>
    <property name="URL">"jdbc:h2:data/testdb"</property>
    <property name="user">"sa"</property>
    <property name="password">""</property>
  </component>
・・・
</components>

DB の準備

今回は、H2 を DB に使用したので、アプリケーションを実行するカレントディレクトリで H2 の h2.bat ファイルを実行し、jdbc.dicon で設定した内容で接続、次のような SQL を実行してテーブルを作成。

CREATE TABLE DEPT(ID INT IDENTITY PRIMARY KEY , DEPT_NO INT, DEPT_NAME VARCHAR(50), LOC VARCHAR(255), VERSION_NO INT);

サンプルアプリケーションの作成

エンティティクラスの作成

DB のテーブルに対するエンティティクラスを JPAアノテーションを使って作成。

package woz.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Version;

@Entity
public class Dept {

    @Id
    @GeneratedValue
    public Integer id;

 // Column アノテーションは不要
 // @Column(name = "DEPT_NO")
    public Integer deptNo;

 // @Column(name = "DEPT_NAME")
    public String deptName;

    public String loc;

    @Version
 // @Column(name = "VERSION_NO")
    public Integer versionNo;
}
サービスクラスの作成

エンティティクラスを操作するための簡単なサービスインターフェースとその実装クラスを作成。

package woz.service;

import woz.entity.Dept;

public interface SampleService {

    int add(String name);

    Dept find(int id);
}

サービスの実装クラスで S2JDBC の胆である JdbcManager クラスを使った DB の処理を実装する。

package woz.service.impl;

import java.util.List;

import org.seasar.extension.jdbc.JdbcManager;

import woz.entity.Dept;
import woz.service.SampleService;

public class SampleServiceImpl implements SampleService {

    //自動的に DI される
    public JdbcManager jdbcManager;

    public int add(String name) {

        Dept dept = new Dept();
        dept.deptNo = 1;
        dept.deptName = name;

        this.jdbcManager.insert(dept).execute();

        return dept.id;
    }

    public Dept find(int id) {
        //1件取得する場合は getSingleResult() が便利、0件の時は null が返る
        return this.jdbcManager.from(Dept.class).where("id = ?", id).getSingleResult();

    //  List<Dept> result = this.jdbcManager.from(Dept.class).where("id = ?", id).getResultList();
    //  return (result.size() == 0)? null: result.get(0);
    }
}
テストクラスの作成

サービスクラスを実行するテストクラスを通常のアプリケーションとして作成

package test;

import org.seasar.framework.container.SingletonS2Container;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;

import woz.entity.Dept;
import woz.service.SampleService;

public class Test {

    public static void main(String[] args) {

        SingletonS2ContainerFactory.init();

        SampleService service = SingletonS2Container.getComponent(SampleService.class);

        int id = service.add("テスト");

        Dept dept = service.find(id);

        System.out.printf("%d : %s", id, dept.deptName);
    }
}

以下の jar ファイルをクラスパスに設定し、コンパイルと Test クラスの実行を行えば、DB へのレコードの挿入と検索の実行を確認できる。

  • seasar2/lib 内の jar ファイル
  • s2-tiger/lib 内の jar ファイル
  • h2.jar ファイル