spring+atomikos+mybatis 多数据源事务(动态切换)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:
注:自动切换,是为不同的数据源,却要对应相同的dao层;

1.与无事务版的一样,创建DynamicDataSource类,继承AbstractRoutingDataSource

package com.test.main.dataSource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceHolder.getDataSource();
    }

}
创建辅助类DynamicDataSourceHolder,主要用于保存当前线程所需的datasource的key值

package com.test.main.dataSource;

public class DynamicDataSourceHolder {
    private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>();

    public static String getDataSource() {
        return THREAD_DATA_SOURCE.get();
    }

    public static void setDataSource(String dataSource) {
        THREAD_DATA_SOURCE.set(dataSource);
    }

    public static void clearDataSource() {
        THREAD_DATA_SOURCE.remove();
    }
}

创建dao层切面,注解选择数据源DataSourceAspect类:

package com.test.main.dataSource;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import com.test.main.annotations.DataSource;

@Component
@Aspect
public class DataSourceAspect {
    @Before("execution(* com.test.model.dao.*.*.*(..))")
    public void intercept(JoinPoint point) throws Exception {
        Class<?> target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        for (Class<?> clazz : target.getInterfaces()) {
            resolveDataSource(clazz, signature.getMethod());
        }
        resolveDataSource(target, signature.getMethod());

    }
    private void resolveDataSource(Class<?> clazz, Method method) {
        String sourceName = null;
        try {
            Class<?>[] types = method.getParameterTypes();
            if (clazz.isAnnotationPresent((Class<? extends Annotation>) DataSource.class)) {
                DataSource source = clazz.getAnnotation(DataSource.class);
                sourceName = source.value();
                DynamicDataSourceHolder.setDataSource(sourceName);
            }
            Method m = clazz.getMethod(method.getName(), types);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                DataSource source = m.getAnnotation(DataSource.class);
                sourceName = source.value();
                DynamicDataSourceHolder.setDataSource(sourceName);
            }
        } catch (Exception e) {
            System.out.println(clazz + ":" + e.getMessage());
        }
    }

}
2.spring-db.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:util="http://www.springframework.org/schema/util"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">

    <util:properties id="jdbc"
        location="classpath:etc/mybatis/db.properties" />

    <!-- 连接池配置开始 -->
    <bean id="chicken" class="com.atomikos.jdbc.AtomikosDataSourceBean"
        init-method="init" destroy-method="close">
        <property name="xaDataSourceClassName"
            value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
        <property name="uniqueResourceName" value="mysql/chicken" />
        <property name="xaProperties">
            <props>
                <prop key="user">#{jdbc.username}</prop>
                <prop key="password">#{jdbc.password}</prop>
                <prop key="url">#{jdbc.chicken}</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="test_chicken" class="com.atomikos.jdbc.AtomikosDataSourceBean"
        init-method="init" destroy-method="close">
        <property name="xaDataSourceClassName"
            value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
        <property name="uniqueResourceName" value="mysql/test_chicken" />
        <property name="xaProperties">
            <props>
                <prop key="user">#{jdbc.username}</prop>
                <prop key="password">#{jdbc.password}</prop>
                <prop key="url">#{jdbc.c_test}</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="fariyking" class="com.atomikos.jdbc.AtomikosDataSourceBean"
        init-method="init" destroy-method="close">
        <property name="xaDataSourceClassName"
            value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
        <property name="uniqueResourceName" value="mysql/fariyking" />
        <property name="xaProperties">
            <props>
                <prop key="user">#{jdbc.username}</prop>
                <prop key="password">#{jdbc.password}</prop>
                <prop key="url">#{jdbc.fariyking}</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="test_fariyking" class="com.atomikos.jdbc.AtomikosDataSourceBean"
        init-method="init" destroy-method="close">
        <property name="xaDataSourceClassName"
            value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
        <property name="uniqueResourceName" value="mysql/test_fariyking" />
        <property name="xaProperties">
            <props>
                <prop key="user">#{jdbc.username}</prop>
                <prop key="password">#{jdbc.password}</prop>
                <prop key="url">#{jdbc.f_test}</prop>
            </props>
        </property>
        <property name="minPoolSize" value="5" />
        <property name="maxPoolSize" value="20" />
        <property name="maxIdleTime" value="60" />
        <property name="reapTimeout" value="20000" />
    </bean>


    <!-- 连接池配置结束 -->

    <!-- MyBatis整合开始 -->

    <bean id="c_dynamicDataSource" class="com.test.main.dataSource.DynamicDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="chicken" value-ref="chicken"></entry>
                <entry key="test_chicken" value-ref="test_chicken"></entry>
            </map>
        </property>
    </bean>
    <bean id="cFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="c_dynamicDataSource" />
        <property name="configLocation" value="classpath:etc/mybatis/mybatis-config.xml" />
        <property name="mapperLocations" value="classpath:com/test/**/*.xml" />
    </bean>    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.test.model.dao.c" />
        <property name="annotationClass" value="com.test.main.annotations.MyBatisRepository" />
        <property name="sqlSessionFactory" ref="cFactory"></property>
        <property name="sqlSessionFactoryBeanName" value="cFactory"></property>
    </bean>
    
    <bean id="f_dynamicDataSource" class="com.test.main.dataSource.DynamicDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="fariyking" value-ref="fariyking"></entry>
                <entry key="test_fariyking" value-ref="test_fariyking"></entry>
            </map>
        </property>
    </bean>
    <bean id="fFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="f_dynamicDataSource" />
        <property name="configLocation" value="classpath:etc/mybatis/mybatis-config.xml" />
        <property name="mapperLocations" value="classpath:com/test/**/*.xml" />
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.test.model.dao.f" />
        <property name="annotationClass" value="com.test.main.annotations.MyBatisRepository" />
        <property name="sqlSessionFactory" ref="fFactory"></property>
        <property name="sqlSessionFactoryBeanName" value="fFactory"></property>
    </bean>
    <!-- MyBatis整合结束 -->


    <!-- 配置数据库事务开始 -->
    <!-- atomikos事务管理器 -->
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
        init-method="init" destroy-method="close">
        <description>UserTransactionManager</description>
        <property name="forceShutdown">
            <value>true</value>
        </property>
    </bean>
    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
        <property name="transactionTimeout" value="3000" />
    </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" />
    <!-- 配置数据库事务结束 -->

</beans>

2.1在同一个事务中,不同的数据源需要不同 SqlSessionFactoryBean,注意配置时,需要配置 MapperScannerConfigurer的:


<property name="sqlSessionFactoryBeanName" value="cFactory"></property>

value值为:SqlSessionFactoryBean 的 bean id;

2.2同一事务中的SqlSessionFactoryBean,对应MapperScannerConfigurer 中的 basePackage 不能范围重合,不然在同一事务时,spring不会切换数据源,而是取先前与之重合的SqlSessionFactoryBean的数据源









本文转自yunlielai51CTO博客,原文链接:http://blog.51cto.com/4925054/2046456,如需转载请自行联系原作者


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
Mybatis+mysql动态分页查询数据案例——测试类HouseDaoMybatisImplTest)
Mybatis+mysql动态分页查询数据案例——测试类HouseDaoMybatisImplTest)
21 1
|
1月前
|
Java 关系型数据库 数据库连接
Mybatis+MySQL动态分页查询数据经典案例(含代码以及测试)
Mybatis+MySQL动态分页查询数据经典案例(含代码以及测试)
26 1
|
1月前
Mybatis+mysql动态分页查询数据案例——条件类(HouseCondition)
Mybatis+mysql动态分页查询数据案例——条件类(HouseCondition)
15 1
|
1月前
Mybatis+mysql动态分页查询数据案例——分页工具类(Page.java)
Mybatis+mysql动态分页查询数据案例——分页工具类(Page.java)
22 1
|
1月前
Mybatis+mysql动态分页查询数据案例——房屋信息的实现类(HouseDaoMybatisImpl)
Mybatis+mysql动态分页查询数据案例——房屋信息的实现类(HouseDaoMybatisImpl)
22 2
|
1月前
|
SQL Java 数据库连接
挺详细的spring+springmvc+mybatis配置整合|含源代码
挺详细的spring+springmvc+mybatis配置整合|含源代码
42 1
|
17天前
|
安全 数据安全/隐私保护
Springboot+Spring security +jwt认证+动态授权
Springboot+Spring security +jwt认证+动态授权
|
1月前
Mybatis+mysql动态分页查询数据案例——工具类(MybatisUtil.java)
Mybatis+mysql动态分页查询数据案例——工具类(MybatisUtil.java)
15 1
|
28天前
|
敏捷开发 监控 前端开发
Spring+SpringMVC+Mybatis的分布式敏捷开发系统架构
Spring+SpringMVC+Mybatis的分布式敏捷开发系统架构
66 0
|
1月前
|
Java 数据库连接 mybatis
Mybatis+mysql动态分页查询数据案例——Mybatis的配置文件(mybatis-config.xml)
Mybatis+mysql动态分页查询数据案例——Mybatis的配置文件(mybatis-config.xml)
20 1