Seasar DI Container with AOP

本ドキュメントはS2.4.0について記述しています.旧バージョンについては該当バージョンの配布ファイルに含まれているドキュメントを参照してください.

S2DBCPの機能を使って、コネクションプーリングを実現できます。JTAと連動するので、トランザクション中にコネクションを取得し閉じるということを何度か行っても、トランザクションは維持されます。JDBCで行っていたようなトランザクションを維持したいがために複数のクラスでコネクションを持ちまわるようなことはもう必要なくなります。S2Txを使えば、トランザクションもAspectで自動的に処理することができます。

セットアップ

XADataSource、ConnectionPoolの設定をおこないます。JDBC DriverがXADataSourceの機能を提供している場合は、 それをそのまま使えますが、提供されていない場合、S2で用意しているXADataSourceImplを使って、XAの機能をエミュレートします。

org.seasar.extension.dbcp.impl.XADataSourceImpl

プロパティ 説明
driverClassName JDBC Driverのクラス名 "oracle.jdbc.driver.OracleDriver"
URL RDBMS固有のURL "jdbc:oracle:thin:@xxx:1521:yyy"
user ユーザ名 "hoge"
password パスワード "password"

org.seasar.extension.dbcp.impl.ConnectionPoolImpl

プロパティ 説明
XADataSource

XADataSourceのインスタンスを設定します。S2Containerで設定する場合は、XADataSourceのコンポーネント名を設定します。
必須です。

xaDataSource
transactionManager TransactionManagerのインスタンスを設定します。S2Containerで設定する場合は、TransactionManagerのコンポーネント名を設定します。
必須です。
transactionManager
timeout プールに戻されたコネクションがここで指定された秒数以上未使用だった場合、物理的にクローズされて破棄されます。
デフォルトは600(10分)です。
600
maxPoolSize 同時にアクティブになれる コネクションの数を指定します。 この数を超える要求があると、コネクションがプールに返されるまで その要求はブロックされます。
0を設定するとコネクションはプールされず、コネクションの取得要求はブロックされません。
デフォルトは10です。
10
allowLocalTx JTAによって制御されない、JDBCのローカルトランザクションを許可する (true) しない (false) を指定します。
falseを指定すると、JTAによるトランザクションが開始されていない状態でコネクションの取得が行われた場合に例外 (java.lang.IllegalStateException) がスローされます。
開発時にfalseを指定すると、S2Txが提供するトランザクション・インターセプタの設定漏れを確実に検出することができます。
デフォルトはtrueです。
true

コンポーネントの設定は以下のようになります。環境に合わせて書き換えてください。

jdbc.dicon

<components namespace="jdbc">
    <include path="jta.dicon"/>
    <component name="xaDataSource"
            class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
        <property name="driverClassName">
            "oracle.jdbc.driver.OracleDriver"
        </property>
        <property name="URL">
            "jdbc:oracle:thin:@xxx:1521:yyy"
        </property>
        <property name="user">"aaa"</property>
        <property name="password">"bbb"</property>
    </component>
    <component name="connectionPool"
            class="org.seasar.extension.dbcp.impl.ConnectionPoolImpl">
        <property name="timeout">600</property>
        <property name="maxPoolSize">10</property>
        <property name="allowLocalTx">true</property>
        <destroyMethod name="close"/>>
    </component>
    <component name="dataSource"
       class="org.seasar.extension.dbcp.impl.DataSourceImpl"/>
</components>

Example

EmployeeDao.java

package examples.dbcp;

import java.sql.SQLException;

public interface EmployeeDao {

    public String getEmployeeName(int empno) throws SQLException;
}

EmployeeDaoImpl.java

package examples.dbcp;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

public class EmployeeDaoImpl implements EmployeeDao {

    private DataSource dataSource_;

    public EmployeeDaoImpl(DataSource dataSource) {
        dataSource_ = dataSource;
    }

    public String getEmployeeName(int empno) throws SQLException {
        String ename = null;
        Connection con = dataSource_.getConnection();
        try {
            PreparedStatement ps = con.prepareStatement(
                "SELECT ename FROM emp WHERE empno = ?");
            try {
                ps.setInt(1, empno);
                ResultSet rs = ps.executeQuery();
                try {
                    if (rs.next()) {
                        ename = rs.getString("ename");
                    }
                } finally {
                    rs.close();
                }
            } finally {
                ps.close();
            }
        } finally {
            con.close();
        }
        return ename;
    }
}

EmployeeService.java

package examples.dbcp;

import java.sql.SQLException;

public interface EmployeeService {

    public String getEmployeeName(int empno) throws SQLException;
}

EmployeeServiceImpl.java

package examples.dbcp;

import java.sql.SQLException;

public class EmployeeServiceImpl implements EmployeeService {

    private EmployeeDao dao_;

    public EmployeeServiceImpl(EmployeeDao dao) {
        dao_ = dao;
    }

    public String getEmployeeName(int empno) throws SQLException {
        return dao_.getEmployeeName(empno);
    }
}

Employee.dicon

<components>
<include path="j2ee.dicon"/>
<component class="examples.dbcp.EmployeeDaoImpl"/>
<component class="examples.dbcp.EmployeeServiceImpl">
<aspect>j2ee.requiredTx</aspect>
</component>
</components>

EmployeeClient.java

package examples.dbcp;

import java.sql.SQLException;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;

public class EmployeeClient {

    private static final String PATH =
        "examples/dbcp/Employee.dicon";

    public static void main(String[] args) {
        S2Container container = S2ContainerFactory.create(PATH);
        container.init();
try {
EmployeeService service = (EmployeeService)
container.getComponent(EmployeeService.class);
System.out.println(service.getEmployeeName(7788));
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
container.destroy();
} } }

実行結果

DEBUG 2004-03-21 12:51:35,653 [main] Transaction.begin()
DEBUG 2004-03-21 12:51:37,075 [main] Transaction.commit()
SCOTT

これまで、JTAやJTAと連動したコネクションプールに対して、敷居が高いなぁと感じていた方も、POJOでこんなに簡単に利用できるということが分かっていただけたと思います。