zoukankan      html  css  js  c++  java
  • spring mvc 多数据源切换,不支持事务控制[一]

    一个项目中需要使用两个数据库,Oracle 和Mysql ,于是参考各个blog,实现此功能.写好后才发现,原来的事务失效了,我去...

    spring-mybatis.xml 配置

        <bean id="configReader" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
            <property name="locations">
                <list>
                    <value>classpath:spring/db.properties</value>
                </list>
            </property>
            <property name="ignoreResourceNotFound" value="true"/>
        </bean>
    
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.oracle.DriverClassName}"></property>
            <property name="jdbcUrl" value="${jdbc.oracle.Url}"></property>
            <property name="user" value="${jdbc.oracle.UserName}"></property>
            <property name="password" value="${jdbc.oracle.UserPassword}"></property>
    
            <property name="acquireIncrement" value="5"></property>
            <property name="initialPoolSize" value="5"></property>
            <property name="maxIdleTime" value="60"></property>
            <property name="maxPoolSize" value="100"></property>
            <property name="minPoolSize" value="5"></property>
        </bean>
    
    
        <!-- 配置数据源:MySQL start -->
        <bean name="mySqlDataSource" class="com.alibaba.druid.pool.DruidDataSource"
              init-method="init" destroy-method="close">
            <property name="driverClassName" value="${jdbc.mysql.DriverClassName}"/>
            <property name="url" value="${jdbc.mysql.Url}"/>
            <property name="username" value="${jdbc.mysql.UserName}"/>
            <property name="password" value="${jdbc.mysql.UserPassword}"/>
    
            <!-- 初始化连接大小 -->
            <property name="initialSize" value="5"/>
            <!-- 连接池最大使用连接数量 -->
            <property name="maxActive" value="30"/>
            <!-- 连接池最小空闲 -->
            <property name="minIdle" value="2"/>
            <!-- 获取连接最大等待时间 -->
            <property name="maxWait" value="300"/>
    
            <property name="validationQuery" value="SELECT 1"/>
            <property name="testOnBorrow" value="false"/>
            <property name="testOnReturn" value="false"/>
            <property name="testWhileIdle" value="true"/>
    
            <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
            <property name="timeBetweenEvictionRunsMillis" value="10000"/>
            <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
            <property name="minEvictableIdleTimeMillis" value="30000"/>
    
            <!-- 打开removeAbandoned功能 -->
            <property name="removeAbandoned" value="true"/>
            <!-- 1800秒,也就是30分钟 -->
            <property name="removeAbandonedTimeout" value="1800"/>
            <!-- 关闭abanded连接时输出错误日志 -->
            <property name="logAbandoned" value="true"/>
    
            <!-- 监控数据库 -->
            <property name="filters" value="stat"/>
        </bean>
    
    
        <bean id="multipleDataSource" class="com.we.database.MultipleDataSource">
            <property name="defaultTargetDataSource" ref="dataSource"/>
            <property name="targetDataSources">
                <map>
                    <entry key="oracleDataSource" value-ref="dataSource"/>
                    <entry key="mySqlDataSource" value-ref="mySqlDataSource"/>
                </map>
            </property>
        </bean>
    
        <!-- oracle myBatis file -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="multipleDataSource"/>
            <!--<property name="configLocation" value="classpath:configuration.xml" /> -->
            <property name="mapperLocations" value="classpath:com/we/dao/mapper/*.xml"/>
        </bean>
    
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.we.dao"/>
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        </bean>
    
    
        <!-- configure transaction -->
        <bean id="transactionManager"
              class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>  后面发现是这里写错了应该是 ref="multipleDataSource"
        </bean>
    
        <!-- annotation transaction -->
        <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
    
    
        <!-- interception transatcion -->
        <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="add*" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
    
        <!-- 配置数据库注解aop -->
        <bean id="dataSourceAspect" class="com.we.database.DataSourceAspect"/>
    
        <aop:config>
            <aop:pointcut id="transactionPointcut" expression="execution(* com.wewe.licai.service..*Impl.*(..))"/>
            <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" order="2"/>
    
            <!--数据源选择切面,保证在事务开始之前执行-->
            <aop:advisor pointcut-ref="transactionPointcut" advice-ref="dataSourceAspect"  order="1" />
        </aop:config>
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD,ElementType.TYPE})
    
    public @interface DataSource {
         String name() default DataSource.oracleDataSource;
         String mySqlDataSource = "mySqlDataSource";
         String oracleDataSource = "oracleDataSource";
    }
    注解切换,默认使用oracle数据源
    /**
     * Created by eastday on 2017/9/21.
     */
    public class DataSourceAspect implements MethodBeforeAdvice,AfterReturningAdvice
    {
    
        @Override
        public void afterReturning(Object returnValue, Method method,
                                   Object[] args, Object target) throws Throwable {
    
            MultipleDataSource.clearDataSource();
        }
    
        @Override
        public void before(Method method, Object[] args, Object target)
                throws Throwable {
    
            //首先取类上的数据源
            if(method.getDeclaringClass().isAnnotationPresent(DataSource.class) && !method.isAnnotationPresent(DataSource.class)) {
    
                DataSource datasource = method.getDeclaringClass().getAnnotation(DataSource.class);
                MultipleDataSource.setDataSource(datasource.name());
    
                //方法上的数据源 优先级高于类上的
            } else if (method.isAnnotationPresent(DataSource.class)) {
    
                DataSource datasource = method.getAnnotation(DataSource.class);
                MultipleDataSource.setDataSource(datasource.name());
            }
            else
            {
                MultipleDataSource.setDataSource(DataSource.oracleDataSource);
            }
        }
    }
    注解方式实现切换数据源,搜索注释,更换注释上面的数据源,支持类注释和方法注释
    public class MultipleDataSource extends AbstractRoutingDataSource {
        private static final ThreadLocal<String> dataSources = new InheritableThreadLocal<String>();
    
        public static void setDataSource(String dataSource) {
            dataSources.set(dataSource);
        }
    
        //清除数据源
        public static void clearDataSource() {
            dataSources.remove();
        }
    
        @Override
        protected Object determineCurrentLookupKey() {
            return dataSources.get();
        }
    }
    继承AbstractRoutingDataSource实现数据源切换
    @DataSource(name = DataSource.mySqlDataSource)
    public class ContentServiceImpl implements IContentService {
    
        @Autowired
        private IContentDao contentDao;
    
        @Override
        public Content queryOne(String type) {
            return contentDao.queryOne(type);
        }
    }
    使用demo
  • 相关阅读:
    Spring Boot 使用 Dom4j XStream 操作 Xml
    Spring Boot 使用 JAX-WS 调用 WebService 服务
    Spring Boot 使用 CXF 调用 WebService 服务
    Spring Boot 开发 WebService 服务
    Spring Boot 中使用 HttpClient 进行 POST GET PUT DELETE
    Spring Boot Ftp Client 客户端示例支持断点续传
    Spring Boot 发送邮件
    Spring Boot 定时任务 Quartz 使用教程
    Spring Boot 缓存应用 Memcached 入门教程
    ThreadLocal,Java中特殊的线程绑定机制
  • 原文地址:https://www.cnblogs.com/eastday/p/7608455.html
Copyright © 2011-2022 走看看