zoukankan      html  css  js  c++  java
  • AbstractRoutingDataSource -- Spring提供的轻量级数据源切换方式

    AbstractRoutingDataSource 只支持单库事务,也就是说切换数据源要在开启事务之前执行。 spring DataSourceTransactionManager进行事务管理,开启事务,会将数据源缓存到DataSourceTransactionObject对象中进行后续的commit rollback等事务操作。
    出现多数据源动态切换失败的原因是因为在事务开启后,数据源就不能再进行随意切换了,也就是说,一个事务对应一个数据源。

    1.传统的Spring管理事务是放在Service业务层操作的,所以更换数据源的操作要放在这个操作之前进行。也就是切换数据源操作放在Controller层,可是这样操作会造成Controller层代码混乱的结果。
    故而想到的解决方案是将事务管理在数据持久 (Dao层) 开启,切换数据源的操作放在业务层进行操作,就可在事务开启之前顺利进行数据源切换,不会再出现切换失败了。
    2.如果管理事务是放在Service业务层操作的,Spring事务会在方法前获取数据连接connection,动态数据源的切面是在Dao层,但是这时还没有到DAO层进行路由选择,因此需要延迟加载数据源,需要用到LazyConnectionDataSourceProxy

    <bean id="parentDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
            <property name="driverClassName" value="${jdbc.driverClassName}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
            <property name="initialSize" value="1"/>
            <property name="minIdle" value="2"/>
            <property name="validationQuery" value="SELECT 1 FROM DUAL"/>
            <property name="testOnCreate" value="true"/>
            <property name="testWhileIdle" value="true"/>
            <property name="testOnBorrow" value="true"/>
        </bean>
    
    
        <bean id="dataSource" parent="parentDataSource">
            <property name="driverClassName" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>
    
        <bean id="dataSourceM2" parent="parentDataSource">
            <property name="driverClassName" value="${jdbcM2.driverClassName}"/>
            <property name="url" value="${jdbcM2.url}"/>
            <property name="username" value="${jdbcM2.username}"/>
            <property name="password" value="${jdbcM2.password}"/>
        </bean>
    
        <bean id="dataSourceR" parent="parentDataSource">
            <property name="driverClassName" value="${jdbcR.driverClassName}" />
            <property name="url" value="${jdbcR.url}" />
            <property name="username" value="${jdbcR.username}" />
            <property name="password" value="${jdbcR.password}" />
        </bean>
    
        <bean id="dynamicDataSource" class="com.cmcc.open.ss.config.DynamicDataSource">
            <property name="targetDataSources">
                <map key-type="java.lang.String">
                    <entry key="dataSource" value-ref="dataSource"/>
                    <entry key="dataSourceM2" value-ref="dataSourceM2"/>
                    <entry key="dataSourceR" value-ref="dataSourceR"/>
                </map>
            </property>
            <property name="defaultTargetDataSource" ref="dataSource"/>
        </bean>
    
        <!-- Spring事务会在方法前获取数据连接connection,但是这时还没有到DAO层进行路由选择,因此需要延迟加载数据源,需要用到LazyConnectionDataSourceProxy。 -->
        <bean id="lazyDataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
            <property name="targetDataSource" ref="dynamicDataSource">
            </property>
        </bean>
    
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="lazyDataSource"/>
            <property name="configLocation" value="classpath:acs_mysql.xml"></property>
        </bean>
    
        <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
            <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
        </bean>
    
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="lazyDataSource"/>
        </bean>
    
        <tx:annotation-driven transaction-manager="transactionManager"/>
    
    

    3.如果不用LazyConnectionDataSourceProxy,可以给切面类上加上@Order(-1),让此切面优先于事务的切面执行

    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    @Component
    @Slf4j
    @Aspect
    @Order(-1)
    public class DataSourceAspect {
        /**
         *
         */
        @Pointcut("@within(com.hy.api.aop.DataSource) || @annotation(com.hy.api.aop.DataSource)")
        public void pointCut() {
    
        }
    
        /**
         *
         * @param dataSource
         */
        @Before("pointCut() && @annotation(dataSource)")
        public void doBefore(DataSource dataSource) {
            String ds = dataSource.value().getValue();
            log.info("====================dataSource: " + ds);
            MultipleDataSource.setDataSource(ds);
    
        }
    
        /**
         * 
         */
        @After("pointCut()")
        public void doAfter() {
            MultipleDataSource.clear();
        }
    }
    
    

    https://blog.csdn.net/qq_37502106/article/details/91044952

  • 相关阅读:
    _ 下划线 Underscores __init__
    Page not found (404) 不被Django的exception中间件捕捉 中间件
    从装修儿童房时的门锁说起
    欧拉定理 费马小定理的推广
    线性运算 非线性运算
    Optimistic concurrency control 死锁 悲观锁 乐观锁 自旋锁
    Avoiding Full Table Scans
    批量的单向的ssh 认证
    批量的单向的ssh 认证
    Corrupted MAC on input at /usr/local/perl/lib/site_perl/5.22.1/x86_64-linux/Net/SSH/Perl/Packet.pm l
  • 原文地址:https://www.cnblogs.com/zhangww/p/12510753.html
Copyright © 2011-2022 走看看