Spring+atmikos多數據源事務一致性

1、pom.xml

<atomikos.version>4.0.2</atomikos.version>

<dependency>
	<groupId>javax.transaction</groupId>
	<artifactId>jta</artifactId>
	<version>1.1</version>
</dependency>
<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>atomikos-util</artifactId>
	<version>${atomikos.version}</version>
</dependency>
<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>transactions</artifactId>
	<version>${atomikos.version}</version>
</dependency>
<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>transactions-jta</artifactId>
	<version>${atomikos.version}</version>
</dependency>
<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>transactions-jdbc</artifactId>
	<version>${atomikos.version}</version>
</dependency>
<dependency>
	<groupId>com.atomikos</groupId>
	<artifactId>transactions-api</artifactId>
	<version>${atomikos.version}</version>
</dependency>

2、多數據源:

 

public class DynamicDataSourceContextHolder
{
    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);

    /**
     * 使用ThreadLocal維護變量,ThreadLocal爲每個使用該變量的線程提供獨立的變量副本,
     *  所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。
     */
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    /**
     * 設置數據源的變量
     */
    public static void setDateSoureType(String dsType)
    {
        log.info("切換到{}數據源", dsType);
        CONTEXT_HOLDER.set(dsType);
    }

    /**
     * 獲得數據源的變量
     */
    public static String getDateSoureType()
    {
        return CONTEXT_HOLDER.get();
    }

    /**
     * 清空數據源變量
     */
    public static void clearDateSoureType()
    {
        CONTEXT_HOLDER.remove();
    }
}
@Aspect
@Order(1)
@Component
public class DsAspect
{
    @Pointcut("@annotation(com.test.datasource.Ds)")
    public void dsPointCut()
    {

    }

    @Around("dsPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable
    {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Ds dataSource = method.getAnnotation(Ds.class);
        if (dataSource != null)
        {
            DynamicDataSourceContextHolder.setDateSoureType(dataSource.value().name());
        }
        try
        {
            return point.proceed();
        }
        finally
        {
            // 銷燬數據源 在執行方法之後
            DynamicDataSourceContextHolder.clearDateSoureType();
        }
    }
}

3、創建一個類CustomSqlSessionTemplate繼承org.mybatis.spring.SqlSessionTemplate

並重寫getSqlSessionFactory()方法

4、spring-mybatis.xml


    <bean id="dataSourceA" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close">
        <property name="uniqueResourceName" value="one" />
        <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
        <property name="xaProperties">
            <props>
                <prop key="url">${jdbc.url}</prop>
                <prop key="user">${jdbc.username}</prop>
                <prop key="password">${jdbc.password}</prop>
            </props>
        </property>
        <property name="minPoolSize" value="5" />
        <property name="maxPoolSize" value="20" />
        <property name="maxIdleTime" value="60" />
        <property name="reapTimeout" value="20000" />
    </bean>

    <!--數據源2-->
    <bean id="dataSourceB" class="com.atomikos.jdbc.AtomikosDataSourceBean" destroy-method="close">
        <property name="uniqueResourceName" value="two" />
        <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
        <property name="xaProperties">
            <props>
                <prop key="url">${slave.url}</prop>
                <prop key="user">${slave.username}</prop>
                <prop key="password">${slave.password}</prop>
            </props>
        </property>
        <property name="minPoolSize" value="5" />
        <property name="maxPoolSize" value="20" />
        <property name="maxIdleTime" value="60" />
        <property name="reapTimeout" value="20000" />
    </bean>
  
    <bean id="sqlSessionFactoryA" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSourceA" />  
        <property name="mapperLocations" value="classpath:com/test/**/*.xml"></property>
		<property name="plugins">
			<array>
				<bean class="com.github.pagehelper.PageInterceptor">
					<property name="properties">
                    	<value>
                        helperDialect=mysql
                        reasonable=true
                        supportMethodsArguments=true
                        params=count=countSql
                        autoRuntimeDialect=true
                    	</value>
                	</property>
				</bean>
			</array>
		</property>
    </bean>
    
    <bean id="sqlSessionFactoryB" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSourceB" />  
        <property name="mapperLocations" value="classpath:com/test/**/*.xml"></property>
		<property name="plugins">
			<array>
				<bean class="com.github.pagehelper.PageInterceptor">
					<property name="properties">
                    	<value>
                        helperDialect=mysql
                        reasonable=true
                        supportMethodsArguments=true
                        params=count=countSql
                        autoRuntimeDialect=true
                    	</value>
                	</property>
				</bean>
			</array>
		</property>
    </bean>
    
    <bean id="sqlSessionTemplate" class="com.test.datasource.CustomSqlSessionTemplate">
        <constructor-arg ref="sqlSessionFactoryA" />
        <property name="targetSqlSessionFactorys">
            <map>
                <entry key="MASTER" value-ref="sqlSessionFactoryA" />
                <entry key="SLAVE" value-ref="sqlSessionFactoryB" />
            </map>
        </property>
    </bean>
	
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
        <property name="basePackage" value="com.test.**.mapper" /> 
        <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"></property>  
    </bean>
  
    <!-- 定義事務 -->  
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"  
          init-method="init" destroy-method="close">  
        <property name="forceShutdown">  
            <value>true</value>  
        </property>  
    </bean>  
  
    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">  
        <property name="transactionTimeout" value="300" />  
    </bean>  
  
    <bean id="springTransactionManager"  
          class="org.springframework.transaction.jta.JtaTransactionManager">  
        <property name="transactionManager">  
            <ref bean="atomikosTransactionManager" />  
        </property>  
        <property name="userTransaction">  
            <ref bean="atomikosUserTransaction" />  
        </property>  
        <property name="allowCustomIsolationLevels" value="true"/>  
    </bean>  
    
    <tx:annotation-driven transaction-manager="springTransactionManager" proxy-target-class="true" order="2" />
	

5、service方面:

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章