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


    注:自动切换,是为不同的数据源,却要对应相同的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="base" class="com.alibaba.druid.pool.xa.DruidXADataSource"
            destroy-method="close" lazy-init="true">
            <property name="initialSize" value="5" />
            <property name="minIdle" value="5" />
            <property name="maxActive" value="20" />
    
            <property name="validationQuery" value="SELECT 1" />
            <property name="timeBetweenEvictionRunsMillis" value="2800000" />
            <property name="minEvictableIdleTimeMillis" value="600000" />
            <property name="testWhileIdle" value="true" />
            <property name="testOnBorrow" value="false" />
            <property name="testOnReturn" value="false" />
            <property name="filters" value="stat" />
    
            <property name="logAbandoned" value="true" />     
        </bean>
        
        <!-- Druid连接池 -->
        <bean id="jpcar" parent="base">
            <property name="driverClassName" value="#{jdbc.driverClassName}" />
            <property name="url" value="#{jdbc.jpcar_url}" />
            <property name="username" value="#{jdbc.username}" />
            <property name="password" value="#{jdbc.password}" />
        </bean>
        <bean id="jpcarAtom" class="com.atomikos.jdbc.AtomikosDataSourceBean"
            init-method="init" destroy-method="close">
            <property name="uniqueResourceName" value="mysql/jpcar" />
            <property name="xaDataSource" ref="jpcar" />
            <property name="maintenanceInterval" value="28000" />
            <property name="testQuery" value="SELECT 1" />
        </bean>
        <bean id="jpcarData" parent="base">
            <property name="driverClassName" value="#{jdbc.driverClassName}" />
            <property name="url" value="#{jdbc.jpcarData_url}" />
            <property name="username" value="#{jdbc.username}" />
            <property name="password" value="#{jdbc.password}" />
        </bean>
        <bean id="jpcarDataAtom" class="com.atomikos.jdbc.AtomikosDataSourceBean"
            init-method="init" destroy-method="close">
            <property name="uniqueResourceName" value="mysql/jpcarData" />
            <property name="xaDataSource" ref="jpcarData" />
            <property name="maintenanceInterval" value="28000" />
            <property name="testQuery" value="SELECT 1" />
        </bean>
    
        <bean id="test_jpcar" parent="base">
            <property name="driverClassName" value="#{jdbc.driverClassName}" />
            <property name="url" value="#{jdbc.test_jpcar_url}" />
            <property name="username" value="#{jdbc.test_username}" />
            <property name="password" value="#{jdbc.test_password}" />
            
        </bean>
        <bean id="test_jpcarAtom" class="com.atomikos.jdbc.AtomikosDataSourceBean"
            init-method="init" destroy-method="close">
            <property name="uniqueResourceName" value="mysql/test_jpcar" />
            <property name="xaDataSource" ref="test_jpcar" />
            <property name="maintenanceInterval" value="28000" />
            <property name="testQuery" value="SELECT 1" />
        </bean>
        <bean id="test_jpcarData" parent="base">
            <property name="driverClassName" value="#{jdbc.driverClassName}" />
            <property name="url" value="#{jdbc.test_jpcarData_url}" />
            <property name="username" value="#{jdbc.test_username}" />
            <property name="password" value="#{jdbc.test_password}" />
            
        </bean>
        <bean id="test_jpcarDataAtom" class="com.atomikos.jdbc.AtomikosDataSourceBean"
            init-method="init" destroy-method="close">
            <property name="uniqueResourceName" value="mysql/test_jpcarData" />
            <property name="xaDataSource" ref="test_jpcarData" />
            <property name="maintenanceInterval" value="28000" />
            <property name="testQuery" value="SELECT 1" />
        </bean>
        <!-- 连接池配置结束 -->
    
        <!-- MyBatis整合开始 -->
    
        <bean id="jpcarDataDynamicDataSource" class="com.jpcar.main.dataSource.DynamicDataSource">
            <property name="targetDataSources">
                <map key-type="java.lang.String">
                    <entry key="jpcar" value-ref="jpcarAtom"></entry>
                    <entry key="jpcarData" value-ref="jpcarDataAtom"></entry>
                    <entry key="test_jpcarData" value-ref="test_jpcarDataAtom"></entry>
                    <entry key="test_jpcar" value-ref="test_jpcarData"></entry>
                </map>
            </property>
        </bean>
        <bean id="jpcarDataFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="jpcarDataDynamicDataSource" />
            <property name="configLocation" value="classpath:etc/mybatis/mybatis-config.xml" />
            <property name="mapperLocations" value="classpath:com/**/*.xml" />
        </bean>
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.jpcar" />
            <property name="annotationClass" value="com.jpcar.main.annotations.MyBatisRepository" />
            <property name="sqlSessionFactory" ref="jpcarDataFactory"></property>
            <property name="sqlSessionFactoryBeanName" value="jpcarDataFactory"></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="90000" />
        </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的数据源

  • 相关阅读:
    一步一步学Remoting之四:承载方式(2)<转>
    一步一步学Remoting之五:异步操作<转>
    NET3.0+中使软件发出声音[整理篇]<转>
    Ext Core手册
    一步一步学Remoting之一:从简单开始<转>
    asp.net 常用字符串过滤方法 <转>
    mssql性能优化<转>
    一步一步学Remoting之四:承载方式(1)<转>
    Javascript中最常用的61个经典技巧 <转>
    Js事件对象<转>
  • 原文地址:https://www.cnblogs.com/qingyibusi/p/7009209.html
Copyright © 2020-2023  润新知