zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    算法学习:二分法从入门到精通
    TypeScript筑基笔记一:Visual Studio Code 创建Typescript文件和实时监控
    LeetCode 92. 反转链表 II
    LeetCode 1525. 字符串的好分割数目
    字节跳动-people后台一面面经
    LeetCode 117. 填充每个节点的下一个右侧节点指针 II
    LeetCode 1529. 灯泡开关 IV
    LeetCode 165. 比较版本号
    LeetCode 312. 戳气球
    LeetCode 605. 种花问题
  • 原文地址:https://www.cnblogs.com/malcolmfeng/p/6682449.html
Copyright © 2011-2022 走看看