Spring MVC动态切换数据源(多数据库类型)

  最近由于项目需求,需要将Sql Server 和 Mysql 两种数据库整合到一个项目,项目的用到的框架是SSM。 因此尝试了利用AOP切面来切每次执行的Servcie方法,根据Service所在的包名来实现数据源自动切换。

  1.项目架构如下:

  

  2.在com.jiefupay.database包中建立四个类:

      

    其中 DataSourceContextHolder.java类源码如下:    

package com.jiefupay.datebase;

public class DataSourceContextHolder {
    
     private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
   //设置当前Thread的数据库类型
     public static void setDbType(String dbType) {
            contextHolder.set(dbType);
     }
     //获取当前Thread的数据库类型
     public static String getDbType() {
            return ((String) contextHolder.get());
     }

     public static void clearDbType() {
            contextHolder.remove();
     }

}

    其中,DataSourceName.java源码如下:

package com.jiefupay.datebase;

/**
 * 数据库名称常量类
 */
public class DataSourceName {

    public static final String SQLSERVER_SOURCE = "sqlserver_source";
    public static final String MYSQL_SOURCE = "mysqlSource";
}

     其中,DynamicDataSource.java源码如下:

package com.jiefupay.datebase;

import java.util.logging.Logger;

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

public class DynamicDataSource extends AbstractRoutingDataSource {

     @Override
     public Logger getParentLogger() {
            return null;
     }

     @Override
     protected Object determineCurrentLookupKey() {
            return DataSourceContextHolder.getDbType();
     }
}

    其中,ChangeDBInteceptor.java作为切点的拦截类,获取每次执行的service的全限令名,源码如下:

package com.jiefupay.datebase;

import org.aspectj.lang.ProceedingJoinPoint;

public class ChangDBInterceptor {

    public Object changeDB(ProceedingJoinPoint pjp) throws Throwable {  
        //AOP切点在Service的 包名.类名
        String path=pjp.getTarget().getClass().getName();
        //如果servcie的 包名.类名 包含 agency,那说明需要切换为mysql数据源
        if (path.indexOf("agency")!=-1){
            DataSourceContextHolder.setDbType(DataSourceName.MYSQL_SOURCE);
        }else{
            DataSourceContextHolder.setDbType(DataSourceName.SQLSERVER_SOURCE);
        }
        return pjp.proceed();  
    }  

}

  3.jdbc.properties文件如下:

mysqldriver=com.mysql.jdbc.Driver
mysqlurl=jdbc:mysql://192.168.0.144:3306/mysql?useUnicode=true&characterEncoding=UTF-8
mysqlusername=myusername
mysqlpassword=mypassword

driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
url=jdbc:sqlserver://192.168.0.144:1433;databaseName=sqlserver_source
username=sqlusername
password=sqlpassword

#定义初始连接数
initialSize=4
#定义最大连接数
maxActive=6
#定义最大空闲
maxIdle=2
#定义最小空闲
minIdle=2
#定义最长等待时间
maxWait=60000

  

  4.spring-mybatis.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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/aop
                        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
                        http://www.springframework.org/schema/context  
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd  
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd 
                        http://www.springframework.org/schema/mvc  
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
    
    <!-- 自动扫描 -->
    <context:component-scan base-package="com.jiefupay" >
         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> 
    </context:component-scan>
    
    <!-- 引入配置文件 -->
    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:jdbc.properties" />
    </bean>

    <!-- 多数据源配置 -->
    <bean id ="sqlserver_source" class= "org.apache.commons.dbcp.BasicDataSource" >
        <property name ="driverClassName" value= "${driver}"></property >
        <property name ="url" value="${url}" ></property >
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
        <property name="initialSize" value="${initialSize}"></property>
        <property name="maxActive" value="${maxActive}"></property>
        <property name="maxIdle" value="${maxIdle}"></property>
        <property name="minIdle" value="${minIdle}"></property>
        <property name="maxWait" value="${maxWait}"></property>
    </bean >
    <bean id="mysqlSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="${mysqldriver}" />
        <property name="url" value="${mysqlurl}" />
        <property name="username" value="${mysqlusername}" />
        <property name="password" value="${mysqlpassword}" />
        <property name="initialSize" value="${initialSize}"></property>
        <property name="maxActive" value="${maxActive}"></property>
        <property name="maxIdle" value="${maxIdle}"></property>
        <property name="minIdle" value="${minIdle}"></property>
        <property name="maxWait" value="${maxWait}"></property>
    </bean>

    <!-- 动态配置数据源 -->
    <bean id ="dataSource" class= "com.jiefupay.datebase.DynamicDataSource" >
        <property name ="targetDataSources">
        <map key-type ="java.lang.String">
            <entry value-ref ="newdata_2014" key="sqlserver_source"></entry >
            <entry value-ref ="mysqlSource" key="mysqlSource"></entry >
        </map>
        </property >
        <property name ="defaultTargetDataSource" ref= "sqlserver_source"></property >
    </bean >

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="mapperLocations" value="classpath:com/jiefupay/*/mapper/*.xml"></property>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.jiefupay.*.dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>

    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager"/>
   
    <bean id="changeDBInterceptor" class="com.jiefupay.datebase.ChangDBInterceptor"></bean>  
   
    <!-- 配置AOP切面,所有service作为切点,执行changeDBInterceptor类中的changeDB方法 -->  
    <aop:config proxy-target-class="true"> 
        <aop:pointcut id="txPointcut" expression="execution(* com.jiefupay..service..*Service*.*(..)) or execution(* com.jiefupay.common..*Service*.*(..))" />
        <aop:aspect ref="changeDBInterceptor" order="1">    
            <aop:around pointcut-ref="txPointcut" method="changeDB"/> 
        </aop:aspect>    
    </aop:config>

</beans>
原文地址:https://www.cnblogs.com/malcolmfeng/p/6682449.html