spring多数据源的切换,主要用到的是AbstractRoutingDataSource这个路由类,当我们的自定义的一个路由分发类继承AbstractRoutingDataSource类后,重写determineCurrentLookupKey()这个方法,重写的内容就是我们的分发规则。那么spring在需要选择数据源的时候,就会执行这个方法,然后根据我们的自定义的规则自动进行分发,从而实现多数据源的切换。

  步骤如下:

  1、配置多个数据源

 <!-- 
  <bean id="c3p0DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClass}" />
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}" />
    <property name="user" value="${jdbc.user}" />
    <property name="password" value="${jdbc.password}" />
    <property name="initialPoolSize" value="${c3p0.initialPoolSize}" />
    <property name="minPoolSize" value="${c3p0.minPoolSize}" />
    <property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
    <property name="maxStatements" value="${c3p0.maxStatements}" />
    <property name="checkoutTimeout" value="${c3p0.checkoutTimeout}" />
    <property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
    <property name="idleConnectionTestPeriod" value="${c3p0.idleConnectionTestPeriod}" />
  </bean>
 -->
  <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="${jdbc.jdbcUrl}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" /> <property name="initialSize" value="${druid.initialSize}" />
<property name="minIdle" value="${druid.minIdle}" />
<property name="maxActive" value="${druid.maxActive}" />
<property name="maxWait" value="${druid.maxWait}" /> <property name="timeBetweenEvictionRunsMillis" value="${druid.timeBetweenEvictionRunsMillis}" />
<property name="minEvictableIdleTimeMillis" value="${druid.minEvictableIdleTimeMillis}" />
<property name="validationQuery" value="${druid.validationQuery}" />
<property name="testWhileIdle" value="${druid.testWhileIdle}" />
<property name="testOnBorrow" value="${druid.testOnBorrow}" />
<property name="testOnReturn" value="${druid.testOnReturn}" />
<property name="poolPreparedStatements" value="${druid.poolPreparedStatements}" />
<property name="maxPoolPreparedStatementPerConnectionSize"
value="${druid.maxPoolPreparedStatementPerConnectionSize}" />
<property name="filters" value="${druid.filters}" />
</bean>
<bean id="druidDataSource_1" parent="druidDataSource">
<property name="url" value="${jdbc.jdbcUrl1}" />
</bean>

  2、配置路由器,注意这个odd和even,他就是我们数据源的标识,在AbstractRoutingDataSource路由determineCurrentLookupKey()这个方法中返回哪个,就是用其对应的数据源。如返回"odd"就是用druidDataSource数据源。

<bean id="dataSourcreRouter" class="cn.yyh.router.NMRoutingDataSource">
<property name="targetDataSources">
<map>
<entry key="odd" value-ref="druidDataSource" />
<entry key="even" value-ref="druidDataSource_1" />
</map>
</property>
<property name="defaultTargetDataSource" ref="druidDataSource" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSourcreRouter" />
</bean>

  3、编写AbstractRoutingDataSource路由分发器,这个NMRoutingToken是什么叻?这个NMRoutingToken是一个令牌,他是存储在ThreadLocal中的一个对象。而ThreadLocal其实就是当前线程内的一个map对象。

public class NMRoutingDataSource extends AbstractRoutingDataSource {

    protected Object determineCurrentLookupKey() {
NMRoutingToken token = NMRoutingToken.getCurrentToken();
if (token != null) {
String dataSourceName = token.getDataSourceName();
// 解除令牌
NMRoutingToken.unbindToken();
return dataSourceName;
}
return null;
} }

  4、可以看到,其实NMRoutingToken就是在当前线程中的ThreadLocal存储一个字符串,前面我们就说过determineCurrentLookupKey()返回什么,spring就自动选择其对应的数据源。那么如果我们new NMRoutingToken("odd"),他就会绑定"odd"到ThreadLocal中,然后在determineCurrentLookupKey()取出来返回就可以了。

public class NMRoutingToken {

    private static ThreadLocal<NMRoutingToken> token = new ThreadLocal<NMRoutingToken>();
private String dataSourceName; public String getDataSourceName() {
return dataSourceName;
} public NMRoutingToken(String dataSourceName) {
super();
this.dataSourceName = dataSourceName;
bindToken(this);
} /**
* 绑定令牌对象到当前线程
*/
private static void bindToken(NMRoutingToken t) {
token.set(t);
} /**
* 解除与当前线程绑定的令牌
*/
public static void unbindToken() {
token.remove();
} /**
* 取得与当前线程绑定的令牌
*/
public static NMRoutingToken getCurrentToken() {
return token.get();
} }

  5、测试

public class NMDataSourceTest extends BaseTest {
@Autowired
private UserMapper userMapper;
@Autowired
private IUserService userService; @Test
/**
* 未开启事务
*/
public void testMapper() {
/**
* 不配置任何数据库,使用默认数据库
*/
int count1 = userMapper.getCount();
System.out.println(count1); /**
* 配置任何数据库odd
*/
NMRoutingToken token = new NMRoutingToken("odd");
count1 = userMapper.getCount();
System.out.println(count1); /**
* 配置任何数据库even
*/
token = new NMRoutingToken("even");
count1 = userMapper.getCount();
System.out.println(count1); /**
* 乱配将使用默认数据库
*/
token = new NMRoutingToken("asdf");
count1 = userMapper.getCount();
System.out.println(count1);
} @Test
/**
* 开启事务
* 注意,由于tomcat容器不支持跨库事务,所以在选择数据源,开启事务后就会挂起,
* 就算再次绑定令牌,但它不会再执行NMRoutingDataSource的determineCurrentLookupKey()方法了,
* 所以后续选择数据源是无效的,默认还是第一次选择的数据源
*/
public void testService() {
userService.getNMCount();
}
}
@Transactional(readOnly = true)
public void getNMCount() {
int count1 = -;
/**
* 配置数据库even
*/
new NMRoutingToken("even");
count1 = userMapper.getCount();
System.out.println(count1); /**
* 配置数据库odd无效,默认还是使用even数据源
*/
new NMRoutingToken("odd");
count1 = userMapper.getCount();
System.out.println(count1);
}

实例下载:示例下载

注:此处的令牌里面存储的是一个字符串,此为最简单的分发规则,我们自己手动选择,如果需要根据对象的某些属性进行自动选择,那么可以在令牌中存储对应的对象,然后在路由中取出对应的属性,如id,然后根据我们的规则,动态返回,这样就不需要我们自己指定了。

注意:tomcat等容器不支持跨库事务,所以只能针对单个service进行事务控制。
不能在同一个开启事务的service中同时操作多个数据库。
如:
@Tranctional
AService(){
methodA(){
dataSourceA.insert();
dataSourceB.update();
}
}
AService(){
@Tranctional
methodA(){
dataSourceA.insert();
dataSourceB.update();
}
}
此类写法(在类或方法上开启事务,同时操作多个数据库)都是不允许的,原理请见src/test/java/ResourceTest.java 只能跟别进行事务控制:
Service(){
aService.insert();
bService.update();
}
AService{
@Tranctional
insert();
}
BService{
@Tranctional
update();
}

spring dataSourceRouter自动切换数据源的更多相关文章

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

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

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

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

  3. Spring AOP动态切换数据源

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

  4. spring集成mybatis配置多个数据源,通过aop自动切换

    spring集成mybatis,配置多个数据源并自动切换. spring-mybatis.xml如下: <?xml version="1.0" encoding=" ...

  5. spring+atomikos+mybatis 多数据源事务(动态切换)

    注:自动切换,是为不同的数据源,却要对应相同的dao层: 1.与无事务版的一样,创建DynamicDataSource类,继承AbstractRoutingDataSource package com ...

  6. 一文读懂Spring动态配置多数据源---源码详细分析

    Spring动态多数据源源码分析及解读 一.为什么要研究Spring动态多数据源 ​ 期初,最开始的原因是:想将答题服务中发送主观题答题数据给批改中间件这块抽象出来, 但这块主要使用的是mq消息的方式 ...

  7. 四、Spring Boot 多数据源 自动切换

    实现案例场景: 某系统除了需要从自己的主要数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库,要求可以在任何方法上可以灵活指定具体要操作的数据库.为了在开发中以最简单的方法使用,本文基于注解 ...

  8. 43. Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】

    [视频&交流平台] àSpringBoot视频 http://study.163.com/course/introduction.htm?courseId=1004329008&utm ...

  9. (43). Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】

    在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...

随机推荐

  1. saltstack实战3--配置管理之grains

    grains是什么 grains是minion服务启动后,采集的客户端的一些基本信息,硬件信息,软件信息,网络信息,软件版本等.你可以在minion上自定义一些grains信息. 它是静态的信息,mi ...

  2. 会话跟踪技术——Session

    一.什么是Session Session从用户访问页面开始,到断开与网站连接为止,形成一个会话的生命周期.在会话期间,分配客户唯一的一个SessionID,用来标识当前用户,与其他用户进行区分. Se ...

  3. 初学JSP+Servlet常见的错误

    web编程中常见的错误: 一.404(要访问的资源没有找到) 1.web程序有没有部署(将项目到tomcat中) 2.url有没有写错(包括大小写,包括项目有没有重命名) 3.有没有将jsp/html ...

  4. spark RDD的元素顺序(ordering)测试

    通过实验发现: foreach()遍历的顺序是乱的 但: collect()取到的结果是依照原顺序的 take()取到的结果是依照原顺序的 为什么呢???? 另外,可以发现: take()取到了指定数 ...

  5. 关于java的static关键字

    通常来说,当你创建类时,就是在描述那个类的对象的外观与行为.除非你用new创建那个类的对象,否则,你实际上并未获得任何东西.当你用new来创建对象时,数据存储空间才被分配,其方法才供外界调用. 但是有 ...

  6. TSQL基础(一) - 查询

    select 1.查询一张表(orders)的所以纪录 select * from Orders 2.查询一张表(orders)某字段的所有记录 select OrderID,OrderDate fr ...

  7. 在win7下配置java编译环境变量

    今天刚接触java编程,环境的配置方法比较复杂.好记性不如烂笔头,发个文章记录一下吧. win7系统 Jdk版本1.6 用鼠标右击“我的电脑”->属性->高级->环境变量系统变量-& ...

  8. web服务器顺带网络负载均衡

    Web服务器配置共享文件 文件服务器需要做的 1. 建立共享文件夹,并建立两个子文件夹 2. 创建用户以便访问共享时使用此凭据 3. 共享并给予刚创建的用户读取和写入权限 Web服务器的设置 1. 新 ...

  9. 在Tomcat中配置基于springside的项目

    注意点: Tomcat默认没有配置Transaction,需要在/Conf/Context.xml配置 1 <Transaction factory="org.objectweb.jo ...

  10. C#中实现抽象类里建立静态方法

    这篇文章主要介绍了C#中实现抽象类里建立静态方法,需要的朋友可以参考下   本文简述了C#中实现抽象类里建立静态方法的解决办法,示例程序如下: 1 2 3 4 5 6 public class Tes ...