Spring动态切换数据源配置

1.applicationContext.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:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:p="http://www.springframework.org/schema/p" 
    xsi:schemaLocation="  
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd  
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd  
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
            
    <!-- 自动扫描注入(controller在spring-mvc子容器中加载 ) -->
    <context:component-scan base-package="com.wpao.shop.service" />
    
      <context:property-placeholder location="classpath:jdbc.properties" />
    <!-- 主数据源 -->
    <bean id="masterDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbcDriver}" />
        <property name="url" value="${jdbcUrl}" />
        <property name="username" value="${jdbcUsername}" />
        <property name="password" value="${jdbcPassword}" />
        <property name="maxActive" value="${maxActive}" /><!-- 最大数据库连接数 -->
        <property name="maxIdle" value="${maxIdle}" /><!-- 最大空闲连接数量 -->
        <property name="maxWait" value="${maxWait}" /><!-- 超时等待时间,毫秒 -->
        <property name="testWhileIdle" value="true" /><!-- 连接是否被回收器进行检验 -->
        <property name="testOnBorrow" value="true" /><!-- 是否在从池中取出连接前进行检验 -->
        <property name="validationQuery" value="select 1" />
        <property name="timeBetweenEvictionRunsMillis" value="3600000" /><!-- 每隔多少时间检测一次,毫秒 -->
        <property name="removeAbandoned" value="true" /><!-- 是否自动回收超时连接 -->
         <property name="removeAbandonedTimeout" value="3600" /><!-- 超时时间,单位秒 -->
    </bean>
    <!-- 从数据源 -->
    <bean id="slaveDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${slave_jdbcDriver}" />
        <property name="url" value="${slave_jdbcUrl}" />
        <property name="username" value="${slave_jdbcUsername}" />
        <property name="password" value="${slave_jdbcPassword}" />
        <property name="maxActive" value="${slave_maxActive}" />
        <property name="maxIdle" value="${slave_maxIdle}" />
        <property name="maxWait" value="${slave_maxWait}" />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="true" />
        <property name="validationQuery" value="select 1" />
        <property name="timeBetweenEvictionRunsMillis" value="3600000" />
        <property name="removeAbandoned" value="true" />
         <property name="removeAbandonedTimeout" value="3600" />
    </bean>
    
    <!-- 动态数据源切换80914 -->
    <bean id="dynamicDataSource" class="com.wpao.shop.util.DynamicDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
               <entry key="master" value-ref="masterDataSource" />
               <entry key="slave" value-ref="slaveDataSource" />
            </map>
        </property>
        <property name="defaultTargetDataSource" ref="masterDataSource" />
    </bean>
    

  <!-- 配置事务管理器对象依赖的数据源 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dynamicDataSource" />
    </bean>
    <!-- 开启事务注解驱动 -->
    <tx:annotation-driven />
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
     <property name="dataSource" ref="dynamicDataSource"/>
     <property name="configLocation" value="classpath:myconf.xml" />
     <property name="mapperLocations" value="classpath:com/wpao/shop/mapper/*.xml" />
    </bean>
    
    <!-- 使用AOP进行切入操作 -->
    <bean id="dataSourceAdvice" class="com.wpao.shop.util.DataSourceAdvice" />
    <aop:config>
        <aop:advisor pointcut="execution(* com.wpao.shop.dao.*.*(..))" advice-ref="dataSourceAdvice" />
    </aop:config>
  
    <!-- 配置扫描器(接口及对应的mapper.xml文件) -->
      <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
         <property name="basePackage" value="com.wpao.shop.dao" />
         <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
      </bean>
      
   
</beans> 

2.DataSourceAdvice      AOP切面根据传入的方法名选择数据源

//AOP切面类:
public class DataSourceAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
    
    Logger logger = Logger.getLogger(this.getClass());
    
    //service方法执行之前被调用:
    public void before(Method method, Object[] args, Object target) {
        
        try {
            String inMethdName = (method != null && method.getName() != null) ? method.getName().trim() : "";
            String methodName = inMethdName.toLowerCase();
            if(methodName.startsWith("query")) {
                DataSourceSwitcher.setSlave();
                logger.info("***[shopmm]DataSource-切换:["+inMethdName+"]方法已切换到:slave!");
            }else if(methodName.startsWith("trans")) { //nei
                //方法的内部方法,不做切换!
                logger.info("***[shopmm]DataSource-切换:["+inMethdName+"]内部方法不切换!");
            }else {
                DataSourceSwitcher.setMaster();
                logger.info("***[shopmm]DataSource-切换:["+inMethdName+"]方法已切换回:master!");
            }
        }catch(Exception e) {
            DataSourceSwitcher.setMaster();
            logger.info("***[shopmm]DataSource-切换:出现异常,已切换回:master!Err:"+e.toString());
        }
    }
  
    //service方法执行完之后被调用:
    public void afterReturning(Object arg0, Method method, Object[] args, Object target) {

        try {
            DataSourceSwitcher.clearDataSource();
        }catch(Exception e) {
            logger.info("***[shopmm]Aop-Service执行完成:出现异常("+method.getName()+")!Err:"+e.toString());
        }
    }  
  
    //抛出Exception之后被调用:
    public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {

        try {
            DataSourceSwitcher.clearDataSource();

        }catch(Exception e) {
            logger.info("***[shopmm]Aop-AfterThrowing:出现异常"+e.toString());
        }
    }
  
}  

3.DataSourceSwitcher  设置当前线程上下文中的数据源对象

//数据源选择类:
public class DataSourceSwitcher {
    
    @SuppressWarnings("rawtypes")
    private static final ThreadLocal contextHolder = new ThreadLocal();
  
    @SuppressWarnings("unchecked")
    public static void setDataSource(String dataSource) {
        //Assert.notNull(dataSource, "dataSource cannot be null");  
        contextHolder.set(dataSource);
    }  
  
    public static void setMaster() {
        setDataSource("master");
    }  
  
    public static void setSlave() {
        setDataSource("slave");
    }  

    public static String getDataSource() {
        
        return (String)contextHolder.get();
    }  
  
    public static void clearDataSource() {
        contextHolder.remove();
    }
    
}

4.DynamicDataSource  用于在产生事务之前,在线程上下文获取数据源

//数据源动态切换类:
public class DynamicDataSource extends AbstractRoutingDataSource {
    
    Logger logger = Logger.getLogger(this.getClass());
      
    @Override
    protected Object determineCurrentLookupKey() {
        String dtSoce = DataSourceSwitcher.getDataSource();
        //logger.info("***[shopmm]nowLookupKey:"+dtSoce);
        return dtSoce;
    }

}

5.调用:service配置@Transactional注解,在切入之前会自动装配对应的事务管理器

    @Transactional
    @Override
    public String JoinPaim(String pmNo,BigDecimal chuMon,String logUser,String ipStr) throws Exception {}

猜你喜欢

转载自blog.csdn.net/qq_38331606/article/details/85274066
今日推荐