最近由于项目需求,需要将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>

Spring MVC动态切换数据源(多数据库类型)的更多相关文章

  1. Spring+Mybatis动态切换数据源

    功能需求是公司要做一个大的运营平台: 1.运营平台有自身的数据库,维护用户.角色.菜单.部分以及权限等基本功能. 2.运营平台还需要提供其他不同服务(服务A,服务B)的后台运营,服务A.服务B的数据库 ...

  2. Spring AOP动态切换数据源

    现在稍微复杂一点的项目,一个数据库也可能搞不定,可能还涉及分布式事务什么的,不过由于现在我只是做一个接口集成的项目,所以分布式就先不用了,用Spring AOP来达到切换数据源,查询不同的数据库就可以 ...

  3. Spring学习总结(16)——Spring AOP实现执行数据库操作前根据业务来动态切换数据源

    深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...

  4. spring mvc+mybatis+多数据源切换

    spring mvc+mybatis+多数据源切换,选取oracle,mysql作为例子切换数据源.oracle为默认数据源,在测试的action中,进行mysql和oracle的动态切换. web. ...

  5. Spring + Mybatis 项目实现动态切换数据源

    项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库. 最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法. ...

  6. Spring动态切换数据源及事务

    前段时间花了几天来解决公司框架ssm上事务问题.如果不动态切换数据源话,直接使用spring的事务配置,是完全没有问题的.由于框架用于各个项目的快速搭建,少去配置各个数据源配置xml文件等.采用了动态 ...

  7. Spring Boot 如何动态切换数据源

    本章是一个完整的 Spring Boot 动态数据源切换示例,例如主数据库使用 lionsea 从数据库 lionsea_slave1.lionsea_slave2.只需要在对应的代码上使用 Data ...

  8. 在使用 Spring Boot 和 MyBatis 动态切换数据源时遇到的问题以及解决方法

    相关项目地址:https://github.com/helloworlde/SpringBoot-DynamicDataSource 1. org.apache.ibatis.binding.Bind ...

  9. hibernate动态切换数据源

    起因: 公司的当前产品,主要是两个项目集成的,一个是java项目,还有一个是php项目,两个项目用的是不同的数据源,但都是mysql数据库,因为java这边的开发工作已经基本完成了,而php那边任务还 ...

随机推荐

  1. python select epoll poll的解析

    select.poll.epoll三者的区别 select select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组(在linux中一切事物皆文件 ...

  2. [编织消息框架][JAVA核心技术]动态代理应用8-IRpcReceive实现

    private static Map<Short, Map<Byte, Method>> RECEIVE_METHOD_INFO = new HashMap<>() ...

  3. xxxxxxxxxxxxxx

    一.Linux命令的分类 1.内部命令:属于Shell解释器的一部分 2.外部命令:独立于Shell解释器之外的程序 3.type命令,查看命令是外部命令还是内部命令: [root@www ~]# t ...

  4. 【模板】链式前向星+spfa

    洛谷传送门--分糖果 博客--链式前向星 团队中一道题,数据很大,只能用链式前向星存储,spfa求单源最短路. 可做模板. #include <cstdio> #include <q ...

  5. (function($){….})(jQuery)一种js插件写法

    我们先看第一个括号里边的内容:function($){….},这不就是一个匿名的函数吗?但是它的形参比较奇怪,是$,这里主要是为了不与其它的库冲突. 这样我们就比较容易理解第一个括号内的内容就是定义了 ...

  6. [Oracle]LogMiner工具小结

    (一)LogMiner工具的作用Logminer工具主要用来分析redo log和archive log文件.通过该工具,可以轻松获得Oracle redo log和archive log文件的具体内 ...

  7. 腾讯实习面经(offer)

    腾讯的实习招聘也算是告一段落了.从内推到正式实习生招聘,总结一下.看了这么多面经,也把自己的经历写一下,有需要的朋友可以参考一下.毕竟互帮互助嘛. 内推 腾讯内推的经历比较惨淡,面了三个部门,都跪在一 ...

  8. bzoj4766 文艺计算姬

    Description "奋战三星期,造台计算机".小W响应号召,花了三星期造了台文艺计算姬.文艺计算姬比普通计算机有更多的艺术细胞.普通计算机能计算一个带标号完全图的生成树个数, ...

  9. PhpMyAdmin导入数据库大小限制?

    问题描述: 在phpMyAdmin中导入数据库时,出现问题: 1. 如果按照扩展名.sql导入,提示如下: 没有接收到要导入的数据.可能是文件名没有提交,也可能是文件大小超出 PHP 限制. 2. 如 ...

  10. Dora.Interception: 一个为.NET Core度身定制的AOP框架

    多年从事框架设计开发使我有了一种强迫症,那就是见不得一个应用里频繁地出现重复的代码.之前经常Review别人的代码,一看到这样的程序,我就会想如何将这些重复的代码写在一个地方,然后采用“注入”的方式将 ...