yohjizzz's Blog

I'm a Programmer.

JOTM により Tomcat や Jetty で JTA を利用する。

ObjectWeb で公開されている JOTM
これを利用することで Tomcat や Jetty でも JTA によるトランザクション管理が可能に。

※かなり昔から公開されているらしいけど、今回、初めて触ってみました。

こいつのおかげで、≪Tomcat + PostgreSQL≫でも≪Jetty + MySQL≫でも JTA を選択肢に入れることができる。(気になるのはパフォーマンスか・・・)

とりあえず Spring 上のアプリに JOTM の設定を組み込んでみる。
※JOTM の設定は DI ですべて吸収できるのでアプリケーションプログラムはまったく意識することなく利用できる。


設定(というか方法)は2つ。
  1つは、アプリ(またはDIコンテナ)が直接的に参照する。
  もう1つは、アプリケーションサーバー側に登録して、アプリ(またはDIコンテナ)が JNDI 経由で参照する。

※検証環境: Windows XPJDK (1.4.2_12)、Tomcat (4.1.31)、SpringFramework (2.0.1)、iBATIS (2.3.0.677)、PostgreSQL (8.1)。

≪パターン 1≫ JNDIを使用せずに applicationContext.xml にデータソースを定義するパターン。

以下、applicationContext.xml の記述例。
(以下の org.enhydra.**.* は JOTM と一緒に配布されるライブラリの中にある xapool.jar に含まれている。XA を実装しているらしい。)

<!-- XADataSource を定義・・・ -->
<bean
  id="xaDataSource"
  class="org.enhydra.jdbc.standard.StandardXADataSource"
  singleton="true"
  destroy-method="shutdown"
  lazy-init="default"
  autowire="default"
  dependency-check="default">
  <property name="transactionManager"><ref bean="jotm" /></property>
  <property name="driverName"><value>${dataSource.driverName}</value></property>
  <property name="url"><value>${dataSource.url}</value></property>
  <property name="user"><value>${dataSource.user}</value></property>
  <property name="password"><value>${dataSource.password}</value></property>
</bean>

<!-- XADataSource をラップするデータソースを定義・・・ -->
<bean
  id="dataSource"
  class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
  singleton="true"
  destroy-method="shutdown"
  lazy-init="default"
  autowire="default"
  dependency-check="default">
  <property name="dataSource"><ref bean="xaDataSource" /></property>
</bean>

<!-- JOTM による UserTransaction ファクトリを定義・・・ -->
<bean
  id="jotm"
  class="org.springframework.transaction.jta.JotmFactoryBean"
  singleton="true"
  lazy-init="default"
  autowire="default"
  dependency-check="default" />

<!-- Spring の TransactionManager は JOTM により生成される UserTransaction を参照・・・ -->
<bean
  id="transactionManager"
  class="org.springframework.transaction.jta.JtaTransactionManager"
  singleton="true"
  lazy-init="default"
  autowire="default"
  dependency-check="default">
  <property name="userTransaction"><ref bean="jotm" /></property>
</bean>

≪パターン 2≫ JNDIを使用して applicationContext.xml ではJNDI経由でデータソースを参照するパターン。

Tomcat の場合は、server.xml にて「DataSource」と「UserTransaction」を登録する。

以下、server.xml の記述例。

<GlobalNamingResources>
    ・
    ・
  <Resource name="jdbc/appDS" auth="Container" type="javax.sql.DataSource" />

  <ResourceParams name="jdbc/appDS">
    <parameter><name>factory</name><value>org.objectweb.jndi.DataSourceFactory</value></parameter>
    <parameter><name>url</name><value>jdbc:postgresql://localhost:5432/hoge?charSet=EUC_JP</value></parameter>
    <parameter><name>username</name><value>hoge</value></parameter>
    <parameter><name>password</name><value>hoge</value></parameter>
    <parameter><name>driverClassName</name><value>org.postgresql.Driver</value></parameter>
  </ResourceParams>

  <Resource name="UserTransaction" auth="Container" type="javax.transaction.UserTransaction" />

  <ResourceParams name="UserTransaction">
    <parameter><name>factory</name><value>org.objectweb.jotm.UserTransactionFactory</value></parameter>
    <parameter><name>jotm.timeout</name><value>60</value></parameter>
  </ResourceParams>
    ・
    ・

applicationContext.xml では登録された「DataSource」をJNDI経由で参照する。
「UserTransaction」は JtaTransactionManager がデフォルトの名前 "UserTransaction" で勝手に参照する為、特に設定は不要。

以下、applicationContext.xml の記述例。

<bean
  id="dataSource"
  class="org.springframework.jndi.JndiObjectFactoryBean"
  singleton="true"
  lazy-init="default"
  autowire="default"
  dependency-check="default">
  <property name="jndiName"><value>jdbc/appDS</value></property>
</bean>

※ライブラリの配置場所…
 パターン 1. であれば、特定のアプリが依存するだけなので WEB-INF/lib に配置すればOK。
 パターン 2. であれば、サーバー(今回は Tomcat)が参照するので {TOMCAT_HOME}/common/lib に配置すべき。