주요글: 도커 시작하기
반응형
JOTM을 이용하여 트랜잭션을 처리하는 방법과 Spring 2에서 JOTM을 연동하는 방법을 살펴본다.

Tomcat 5.5와 JOTM 연동

JOTM(Java Open Transaction Manager)은 ObjectWeb에서 제공하는 트랜잭션 관리자로서 JTA, JTS 등의 API를 지원하고 있다. JOTM을 사용하면 기존의 JDBC 기반의 코드에 JTA를 이용한 트랜잭션 처리 코드를 손쉽게 적용할 수 있다. 본 글에서는 DAUM 내에서 많이 사용되고 있는 Tomcat 5.5와 JOTM을 연동하여 트랜잭션을 처리하는 방법과 앞서 살펴봤던 Spring 2.0과 JOTM을 연동하는 방법에 대해서 살펴볼 것이다.

먼저, Tomcat 5.5 버전과 JOTM을 연동하는 방법에 대해서 살펴보도록 하자. Tomcat 5.5와 JOTM을 연동하려면 다음과 같은 순서에 따라 작업을 진행하면 된다.

  1. JOTM 다운로드 및 jar 파일 설치
  2. JOTM 설정 파일 작성
  3. Tomcat 설정: DataSource 및 UserTransaction 설정
  4. 웹 어플리케이션의 web.xml 파일에 DataSource 참고하도록 설정
  5. 코드 작성
JOTM 다운로드 및 jar 파일 설치

JOTM은 http://jotm.objectweb.org/download/index.html 사이트에서 다운로드 받을 수 있다. JOTM을 다운로드 받은 뒤 압축을 풀고, [JOTM]/lib 디레렉토리에 있는 모든 jar 파일을 [Tomcat]/common/lib 디렉토리에 복사한다. 또한, 사용할 DBMS에 알맞은 JDBC 드라이버를 [Tomcat]/common/lib 디렉토리에 복사한다.

JOTM 설정 파일 작성

[Tomcat]/common/classes 디렉토리에 carol.properties 파일을 생성하고 다음과 같이 내용을 작성한다.

carol.protocols=jrmp
carol.start.jndi=false
carol.start.ns=false
carol.start.rmi=false
# carol을 사용하지 않고 Tomcat의 JNDI를 사용하도록 설정
carol.jndi.java.naming.factory.url.pkgs=org.apache.naming

Tomcat 설정: DataSource 및 UserTransaction 설정

JOTM을 설치한 다음에 할 작업은 JOTM이 제공할 DataSource와 UserTransaction을 설정하는 것이다. 다음과 같이 콘텍스트를 위한 <Context> 태그에 DataSource와 UserTransaction을 위한 설정을 추가한다.

<Context path="/jotmtest" debug="0"
  reloadable="true" crossContext="true">
    <!-- Resource configuration for JDBC datasource use XAPool -->
    <Resource name="jdbc/myDB" auth="Container" type="javax.sql.DataSource"
        factory="org.objectweb.jndi.DataSourceFactory"
        driverClassName="com.mysql.jdbc.Driver"
        username="root" password="root" url="jdbc:mysql://localhost:3307/test"/>
    
    <!-- Resource configuration for UserTransaction use JOTM -->
    <Transaction factory="org.objectweb.jotm.UserTransactionFactory"
       jotm.timeout="60"/>
</Context>

org.objectweb.jndi.DataSourceFactory는 ObjectWeb에서 제공되는 XAPool을 사용하여 DataSource를 생성하는 ResourceFactory 이다.

웹 어플리케이션: web.xml 설정

web.xml 파일에 앞서 정의한 DataSource를 참고하도록 다음과 같은 코드를 추가한다.

<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    version="2.4">

  <resource-env-ref>
    <description>DB Connection</description>
    <resource-env-ref-name>jdbc/myDB</resource-env-ref-name>
    <resource-env-ref-type>javax.sql.DataSource</resource-env-ref-type>
  </resource-env-ref>

</web-app>

코드

이제 남은 작업은 JOTM이 제공하는 DataSource와 UserTransaction을 사용하여 트랜잭션 처리를 수행하는 것이다. 아래 코드는 DataSource와 UserTransaction을 사용하는 간단한 JSP 코드이다.

<%@ page contentType="text/html; charset=euc-kr" %>
<%@ page import = "javax.naming.Context" %>
<%@ page import = "javax.naming.InitialContext" %>
<%@ page import = "javax.sql.DataSource" %>
<%@ page import = "javax.transaction.UserTransaction" %>
<%@ page import = "java.sql.Connection" %>
<%@ page import = "java.sql.PreparedStatement" %>
<%
    Context ctx = new InitialContext();
    
    UserTransaction tx = (UserTransaction)ctx.lookup("java:comp/UserTransaction");
    
    DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/myDB");
    
    Connection conn = null;
    PreparedStatement pstmt = null;
    try {
        tx.begin(); // 트랜잭션 시작
        conn = ds.getConnection();
        pstmt = conn.prepareStatement("update user set name = '2222' where id = ?");
        pstmt.setInt(1, 25);
        pstmt.executeUpdate();
        tx.commit(); // 트랜잭션 커밋
        out.println("success");
    } catch(Throwable e) {
        tx.rollback(); // 트랜잭션 롤백
        throw e;
    } finally {
        if (conn != null) conn.close();
    }
%>

JOTM이 분산 트랜잭션을 지원하는 JTA를 구현하고 있기 때문에, 다음과 같이 다수의 DataSource에 대한 트랜잭션 처리도 가능하다.

    Context ctx = new InitialContext();
    
    UserTransaction tx = (UserTransaction)ctx.lookup("java:comp/UserTransaction");
    
    DataSource ds1 = (DataSource)ctx.lookup("java:comp/env/jdbc/myDB1");
    DataSource ds2 = (DataSource)ctx.lookup("java:comp/env/jdbc/myDB2");

    Connection conn1 = null;
    Connection conn2 = null;
    try {
        tx.begin(); // 트랜잭션 시작
        conn1 = ds1.getConnection();
        conn2 = ds2.getConnection();
        ...
        tx.commit(); // 트랜잭션 커밋 (2-phase commit)
    } catch(Throwable e) {
        tx.rollback(); // 트랜잭션 롤백
        throw e;
    } finally {
        if (conn1 != null) conn.close();
        if (conn2 != null) conn.close();
    }

JOTM과 Spring의 연동

Spring은 JOTM과의 연동을 위한 별도의 클래스를 제공하고 있기 때문에, Spring의 설정 파일만 변경하면 JOTM이 제공하는 트랜잭션 관리 기능을 사용할 수 있다. 아래 코드는 Spring에서 JOTM을 사용하기 위한 설정의 예이다.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
       http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

    <bean id="jotm"
        class="org.springframework.transaction.jta.JotmFactoryBean" />

    <bean id="txManager"
        class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="userTransaction" ref="jotm" />
    </bean>
    <!-- XAPool로 생성한 데이터소스 -->
    <bean id="dataSource"
        class="org.enhydra.jdbc.pool.StandardXAPoolDataSource"
        destroy-method="shutdown">
        <property name="dataSource">
            <bean class="org.enhydra.jdbc.standard.StandardXADataSource"
                destroy-method="shutdown">
                <property name="transactionManager" ref="jotm" />
                <property name="driverName" value="com.mysql.jdbc.Driver" />
                <property name="url"
                          value="jdbc:mysql://localhost:3307/test" />
            </bean>
        </property>
        <property name="user" value="root" />
        <property name="password" value="root" />
    </bean>

    <!-- 트랜잭션을 위한 Advisor 정의 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" />
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="requiredTx"
            expression="execution(* net.daum.cto.ts.techReport.report0.BookingService.*(..))" />
        <!-- txAdvice를 특정 pointcut에 적용 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx" />
    </aop:config>
    ...

만약 iBatis를 사용한다면 XAPool로 생성한 DataSource를 iBatis의 DataSource로 지정해주면 된다. 아래는 iBatis를 사용할 때의 Spring 설정 예이다.

<pre class="code">

    <bean id="sqlMapClient"
        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation"
            value="WEB-INF/sqlmap-config.xml" />
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="bookingService"
        class="net.daum.cto.ts.techReport.report0.BookingServiceImpl">
        <property name="bookingDao" ref="bookingDao" />
    </bean>

    <bean id="bookingDao"
        class="net.daum.cto.ts.techReport.report0.BookingDaoImpl">
        <property name="sqlMapClient" ref="sqlMapClient" />
    </bean>

</beans>

관련링크:

+ Recent posts