最近由于项目需求,需要将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. Tensorflow学习笔记---0--TensorBoard

    运行mnist_with_summaries学习TensorBoard时,由于需要GPU支持,运行窗口报错:Couldn't open CUDA library cupti64_80.dll 解决办法 ...

  2. JQgrid表格的使用

    html部分: <div class="tab"> <table id="datatable"></table>      ...

  3. 【学而思】利用shouldComponentUpdate钩子函数优化react性能以及引入immutable库的必要性

    凡是参阅过react官方英文文档的童鞋大体上都能知道对于一个组件来说,其state的改变(调用this.setState()方法)以及从父组件接受的props发生变化时,会导致组件重渲染,正所谓&qu ...

  4. 计算机网络——DNS协议的学习与实现

    1. 主要内容 不说废话,直接进入正题.先说说本文本文的主要内容,好让你决定是否看下去: 介绍DNS是干什么的: 介绍DNS是如何工作的: 介绍DNS请求与响应的消息格式: 编程实现一个简单的DNS服 ...

  5. Android 开源优秀的项目

    webrtc square/picasso  Android 的一个强大的图像下载和缓存库 A powerful image downloading and caching library for A ...

  6. 【Uva 10498】满意值

    Description Kaykobad教授把为ACM选手买饭的任务交给了Nasa.Nasa决定买n种不同的食物.然后他询问了m名选手对每种食物的需求量.选手们当然不会给出任何符合逻辑的回答,他们只是 ...

  7. 蓝桥杯-手机尾号-java

    /* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...

  8. PHP学习笔记-2

    PHP 是一门弱类型语言: 在上面的实例中,我们注意到,不必向 PHP 声明该变量的数据类型.(跟Javascript很像啊!) PHP 会根据变量的值,自动把变量转换为正确的数据类型. 在强类型的编 ...

  9. iOS关于Cookie验证登录状态

    1.第一次进入应用,登录获取Cookie,此时如果用到的是AFN去获取接口数据,Cookie已经写入了,所以无需处理,每次请求的时候,会自动将该cookie传给后台去验证 2.将Cookie缓存到本地 ...

  10. JavaFx自定义Tab-Order

    title: JavaFx自定义Tab-Order Tab-order是什么?在界面上当你按tab键触发焦点转移的功能,这就是tab order.但是Javafx有个缺陷就是不方便自己设置tab-or ...