DBILITY

spring jta db,file transaction examination 본문

java/spring

spring jta db,file transaction examination

DBILITY 2016. 9. 9. 15:54
반응형
  1. XADiskSessionFactory.java
    테스트를 위해 원저작자의 github을 참고하였습니다.
    package org.xadisk.integration.spring.xadiskspring;
    
    import java.util.Collection;
    import java.util.Collections;
    import java.util.Hashtable;
    import java.util.Map;
    import java.util.WeakHashMap;
    
    import javax.transaction.RollbackException;
    import javax.transaction.Status;
    import javax.transaction.Synchronization;
    import javax.transaction.SystemException;
    import javax.transaction.Transaction;
    import javax.transaction.TransactionManager;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.transaction.jta.JtaTransactionManager;
    import org.xadisk.bridge.proxies.interfaces.XAFileSystem;
    import org.xadisk.bridge.proxies.interfaces.XASession;
    
    import com.sun.java.swing.plaf.windows.WindowsTreeUI.CollapsedIcon;
    
    /**
     * Return current XASession from jtaTransaction
     * 
     * @author AlexisTp https://github.com/AlexisTp/XADisk-spring
     * modify hyperrookie@gmail.com
     */
    public class XADiskSessionFactory {
    	
    	protected static transient Logger LOG = LoggerFactory.getLogger(XADiskSessionFactory.class);
    	private TransactionManager txManager;
    	private XAFileSystem xaFileSystem;	
    	private transient Map<Transaction, XASession> xaSessionMap;
    	
    	public XADiskSessionFactory(JtaTransactionManager jtaTransactionManager, XAFileSystem xaFileSystem) {
    		this.txManager = jtaTransactionManager.getTransactionManager();
    		this.xaFileSystem = xaFileSystem;
    		xaSessionMap = Collections.synchronizedMap(new WeakHashMap<Transaction, XASession>());
    	}
    
    	public XASession getCurrentSession() throws IllegalStateException, RollbackException, SystemException {
    		
    		final Transaction txn = txManager.getTransaction();
    		
    		//synchronized (txn) {
    			XASession session = xaSessionMap.get(txn);
    			if (session == null) {
    				
    				session = xaFileSystem.createSessionForXATransaction();
    				LOG.debug("New XASession has been created");
    				
    				txManager.getTransaction().enlistResource(session.getXAResource());
    				LOG.debug("XASession's XAResource has been enlisted in transaction");
    			
    				txn.registerSynchronization(new Synchronization() {
                        public void beforeCompletion() {
    
                        }
    
                        public void afterCompletion(int status) {
                            xaSessionMap.remove(txn);
                            LOG.debug("XASession has been removed from the XASession Map");
                        }
                    });
    
    				xaSessionMap.put(txn, session);
    				LOG.debug("New XASession added to XASession Map");
    				
    			}else{
    				if (!isInProgress(txn.getStatus())) {
    					LOG.info("Current transaction is not in progress");
    				}
    				LOG.debug("XASession found in XASession Map");
    			}
    
    			return session;
    		//}
    
    	}
    
    	private boolean isInProgress(int status) {
    
    		return status == Status.STATUS_ACTIVE
    				|| status == Status.STATUS_MARKED_ROLLBACK;
    
    	}
    }
  2. pom.xml 추가
    <dependency>
        <groupId>com.atomikos</groupId>
        <artifactId>transactions-jta</artifactId>
        <version>3.8.0</version>
    </dependency>
    <dependency>
        <groupId>com.atomikos</groupId>
        <artifactId>transactions-jdbc</artifactId>
        <version>3.8.0</version>
    </dependency>
    <dependency>
        <groupId>javax.transaction</groupId>
        <artifactId>jta</artifactId>
        <version>1.1</version>
    </dependency>
    <!-- xadisk -->
    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>
    <dependency>
        <groupId>net.java.xadisk</groupId>
        <artifactId>xadisk</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>javax.resource</groupId>
        <artifactId>connector-api</artifactId>
        <version>1.5</version>
    </dependency>
    <dependency>
        <groupId>org.xadisk.integration.spring</groupId>
        <artifactId>xadisk-spring</artifactId>
        <version>1.0.0</version>
    </dependency>
    <!-- JDBC driver -->
    <dependency>
         <groupId>com.microsoft.sqlserver</groupId>
         <artifactId>sqljdbc4</artifactId>
         <version>4.1</version>
     </dependency>
    <dependency>
        <groupId>com.ibm.as400.access</groupId>
        <artifactId>AS400JDBCDriver</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc7</artifactId>
        <version>12.1.0.2</version>
    </dependency>
  3. transaction-context.xml
    <!--?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:tx="http://www.springframework.org/schema/tx" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
     
        <bean id="userTransactionService" class="com.atomikos.icatch.config.UserTransactionServiceImp" init-method="init" destroy-method="shutdownForce">
        <constructor-arg>
            <!-- IMPORTANT: specify all Atomikos properties here -->
            <props>
                <prop key="com.atomikos.icatch.service">com.atomikos.icatch.standalone.UserTransactionServiceFactory</prop>
                <prop key="com.atomikos.icatch.output_dir">log/</prop>
                <prop key="com.atomikos.icatch.log_base_dir">log/</prop>
            </props>
        </constructor-arg>
        </bean>
     
        <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close" depends-on="userTransactionService">
            <property name="forceShutdown" value="false" />      
        </bean>
     
        <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
            <property name="transactionTimeout" value="300" />
        </bean>
     
        <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
            <property name="transactionManager" ref="atomikosTransactionManager" />
            <property name="userTransaction" ref="atomikosUserTransaction" />
            <property name="validateExistingTransaction" value="true" />
        </bean>
     
        <tx:annotation-driven transaction-manager="jtaTransactionManager" />
     
    </beans>
  4. dataSource 추가 (오라클예제이며 각 데이터소스추가)
    <!--?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:mybatis-spring="http://mybatis.org/schema/mybatis-spring" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
     
         <!-- <bean id="dataSource_Oracle" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
            <property name="driverClassName" value="${oracle.jdbc.driver}"/>
            <property name="url" value="${oracle.jdbc.url}"/>
            <property name="username" value="${oracle.jdbc.username}"/>
            <property name="password" value="${oracle.jdbc.password}"/>
            <property name="defaultAutoCommit" value="false"/>
            <property name="initialSize" value="1"/>
            <property name="minIdle" value="1"/>
            <property name="maxIdle" value="2"/>
            <property name="maxActive" value="4"/>
            <property name="maxWait" value="60000"/>
            <property name="testOnBorrow" value="true" />
            <property name="testWhileIdle" value="true" />
            <property name="validationQuery" value="SELECT 1 FROM DUAL" />
            <property name="removeAbandoned" value="true" />
            <property name="removeAbandonedTimeout" value="300" />
            <property name="logAbandoned" value="true" />
        </bean> -->
        <bean id="dataSource_Oracle_XA" class="oracle.jdbc.xa.client.OracleXADataSource" destroy-method="close">
            <property name="URL" value="${oracle.jdbc.url}" />
            <property name="user" value="${oracle.jdbc.username}" />
            <property name="password" value="${oracle.jdbc.password}" />
            <!-- <property name="fastConnectionFailoverEnabled" value="true" /> -->
        </bean>
             
        <bean id="dataSource_Oracle" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
            <property name="uniqueResourceName" value="oracleXA"/>
            <property name="xaDataSource" ref="dataSource_Oracle_XA" />
            <property name="minPoolSize" value="1" />
            <property name="maxPoolSize" value="5" />
            <property name="maxIdleTime" value="6000" />
            <property name="testQuery" value="SELECT 1 FROM DUAL" />
        </bean>
         
        <bean id="dataMySource_Oracle_XA" class="net.sf.log4jdbc.Log4jdbcProxyDataSource">
            <constructor-arg ref="dataSource_Oracle" />
            <property name="logFormatter">
                <bean class="net.sf.log4jdbc.tools.Log4JdbcCustomFormatter">
                    <property name="loggingType" value="MULTI_LINE" />
                    <property name="sqlPrefix" value="SQL:::" />
                </bean>
             
        </bean>
         
        <bean id="sqlSessionFactory_Oracle" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataMySource_Oracle_XA"/>
            <property name="mapperLocations" value="classpath*:config/mapper/**/Oracle_*.xml"/>
            <property name="configLocation" value="classpath:config/mapper/mybatis_config.xml"/>
        </bean>
         
        <bean id="sqlSessionTemplate_Oracle" class="org.mybatis.spring.SqlSessionTemplate">
            <constructor-arg index="0" ref="sqlSessionFactory_Oracle" />
        </bean>
         
        <!-- <tx:annotation-driven transaction-manager="transactionManager"/>
     
        <bean id="transactionManager_Oracle"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource_Oracle"/>
        </bean>  -->
     
    </beans>
  5. transaction-file-context.xml
    <!--?xml version="1.0" encoding="UTF-8"?-->
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
         
        <bean id="xaDiskConfig" class="org.xadisk.filesystem.standalone.StandaloneFileSystemConfiguration">
            <constructor-arg index="0" value=".\log" />
            <constructor-arg index="1" value="test-xaDist-instance-1" />
            <property name="transactionLogFileMaxSize" value="100000" />
            <property name="synchronizeDirectoryChanges" value="false" />
        </bean>
         
        <bean id="xaDiskNativeFS" class="org.xadisk.filesystem.NativeXAFileSystem" factory-method="bootXAFileSystemStandAlone" destroy-method="shutdown">
            <constructor-arg index="0" ref="xaDiskConfig" />
        </bean>
         
        <bean id="xaDiskSessionFactory" class="org.xadisk.integration.spring.xadiskspring.XADiskSessionFactory">
            <constructor-arg index="0" name="txManager" ref="jtaTransactionManager" />
            <constructor-arg index="1" name="xaFileSystem" ref="xaDiskNativeFS" />
        </bean>
         
    </beans>
  6. dummy_mybatis.xml
    
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="DummyMybatis"/>
  7. mybatis_config.xml
    <!--?xml version="1.0" encoding="UTF-8"?-->
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" >
    <configuration>
         
        <settings>
            <setting name="cacheEnabled" value="true" />
            <setting name="lazyLoadingEnabled" value="true" />
            <setting name="aggressiveLazyLoading" value="true" />
            <setting name="useGeneratedKeys" value="true" />
            <setting name="defaultExecutorType" value="BATCH" />
            <setting name="defaultStatementTimeout" value="300" />
            <setting name="localCacheScope" value="SESSION" />
            <setting name="jdbcTypeForNull" value="VARCHAR" />
            <setting name="callSettersOnNulls" value="true" />
        </settings>
         
        <mappers>
            <mapper resource="config/mapper/dummy_mybatis.xml" />
        </mappers>
         
    </configuration>
  8. logback.xml에 logger추가
    <logger name="com.atomikos" additivity="false">
        <level value="debug" />
        <appender-ref ref="console" />
        <appender-ref ref="file" />
    </logger>
    <logger name="org.xadisk" additivity="false">
        <level value="debug" />
        <appender-ref ref="console" />
        <appender-ref ref="file" />
    </logger>
  9. 오라클 XA 연동 시 트랜잭션 복구 권한 설정
    As user SYS, run the following commands on your Oracle server:
    grant select on pending_trans$ to public;
    grant select on dba_2pc_pending to public;
    grant select on dba_pending_transactions to public;
  10. mssql XA설정시 복구권한 설정
    sqlserver의 Binn에 sqljdbc_xa.dll 복사하고,xa_install.sql 실행하여 권한 설정 및 MS_DTC XA설정(참고화면)
  11. 파일트랜잭션용
    @Autowired
    private XADiskSessionFactory sessionFactory;
    
    XASession session = sessionFactory.getCurrentSession();
    
    session.createFile(new File(file_lot_path+"xxa.txt"), false); //이런 식이다...
    exception catch and throw New RuntimeException

뭔가 잘못한 것이겠지만,다량의 XML파일을 생성하고,삭제하는 경우 고속처리 환경에서는 비추였습니다.
정말 많은 시간이 필요한 테스트였기 때문에 기록해 둡니다.

 

반응형
Comments