基于Spring框架的简单多数据源切换解决办法

Spring框架JDBC包提供了一个抽象类AbstractRoutingDataSource提供了动态切换数据库的基础方法。我们仅仅需要实现一个简单的数据源选择算法就可以轻松的利用Spring框架实现数据源切换了。

Spring支持每次被操作的单数据源的事务。

1.继承AbstractRoutingDataSource并实现方法determineCurrentLookupKey()

 package dev.tinyz.datasource;

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

 /**
* Created by TinyZ on 2014/7/28.
*/
public class MultiDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return MultiContextHolder.getDataSourceType();
}
}

2.实现一个数据源选择算法。示例提供了一个简单的代码选择数据源示例

 package dev.tinyz.datasource;

 /**
* Created by TinyZ on 2014/7/28.
*/
public class MultiContextHolder { // 定义数据源 - 每个数据源都要在这里注册
public static final String DATA_SOURCE_1 = "1";// 对应在beans.xml里面注册的数据源的key
public static final String DATA_SOURCE_2 = "2"; // ThreadLocal:用于解决线程安全问题。每个线程都会拥有一个独立的变量副本。线程内部可以独立的改变,而不影响其他线程
public static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static void setDataSourceType(String type) {
contextHolder.set(type);
} public static String getDataSourceType() {
return contextHolder.get();
}
}

3.Spring配置(仅供参考)  **最重要的部分 - 包含了定义多数据源,配置多数据源路由器,设置事务支持

 <?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <!-- Configure all properties files here, wildcards like *.properties are also allowed -->
<!-- <context:property-placeholder location="file:conf/conf.properties" /> --> <!-- 设置数据源 --><!-- BoneCP configuration -->
<bean id="dataSource1" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/black?useUnicode=true&amp;characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="" />
<property name="idleConnectionTestPeriodInMinutes" value="60" />
<property name="idleMaxAgeInMinutes" value="240" />
<property name="maxConnectionsPerPartition" value="10" />
<property name="minConnectionsPerPartition" value="5" />
<property name="partitionCount" value="5" />
<property name="acquireIncrement" value="5" />
<property name="statementsCacheSize" value="100" />
<!--<property name="releaseHelperThreads" value="3" />-->
</bean>
<bean id="dataSource2" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/black1?useUnicode=true&amp;characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="" />
<property name="idleConnectionTestPeriodInMinutes" value="60" />
<property name="idleMaxAgeInMinutes" value="240" />
<property name="maxConnectionsPerPartition" value="10" />
<property name="minConnectionsPerPartition" value="5" />
<property name="partitionCount" value="5" />
<property name="acquireIncrement" value="5" />
<property name="statementsCacheSize" value="100" />
<!--<property name="releaseHelperThreads" value="3" />-->
</bean> <!-- 设置abstractRoutingDataSource注入两个变量 -->
<bean id="dataSource" class="dev.tinyz.datasource.MultiDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="1" value-ref="dataSource1"></entry>
<entry key="2" value-ref="dataSource2"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSource1"/>
</bean> <!-- 设置缓存工厂 - 数据来源于 dataSource -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Spring框架 数据库 JDBC事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Spring框架 事务模板 -->
<bean id="txTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="txManager"></property>
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"></property>
</bean>
<!-- Spring框架 启动使用注解实现声明式事务管理的支持 -->
<tx:annotation-driven transaction-manager="txManager" /> <!-- Server beans --> <!-- 配置容器 不需要任何属性 The Spring application context-->
<bean id="springContext" class="dev.tinyz.config.AppContext"></bean> <!-- Mybatis Bean -->
<bean id="baseMapper" class="org.mybatis.spring.mapper.MapperFactoryBean" abstract="true" lazy-init="true">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<bean id="useMapper" parent="baseMapper">
<property name="mapperInterface" value="dev.tinyz.persistence.mapper.UserMapper"/>
</bean> <!-- 注解配置 -->
<context:annotation-config />
<!-- 注解扫描 基础包-dev.tinyz.persistence -->
<context:component-scan base-package="dev.tinyz.persistence" />
</beans>
dataSource 是我们定义的MultiDataSource的实例。拥有两个属性targetDataSources和defaultTargetDataSource,这两个属性名都不能修改。因为AbstractRoutingDataSource里面设置的参数是依赖Spring注入的。有需要的朋友可以去查看Spring的源码
AppContext 是程序实现的Spring单例。继承ApplicationContextAware
baseMapper 定义了Mybatis-Spring桥里面的一个抽象类。用于子类实现映射接口

4.简单的测试代码(示例)

 // 测试
final UserMapper userMapper = (UserMapper) AppContext.getBean("useMapper");
// 切换到数据源1
MultiContextHolder.setDataSourceType(MultiContextHolder.DATA_SOURCE_1);
// 查询数据库
MemUser tinyz1 = userMapper.selectByAccount("tinyz1");

ps:以下的内容是笔者提供的示例。假如不需要的话,可以忽略。O(∩_∩)O哈哈~。写的很简单。

示例的需求:

操作系统:Win 7 64bit

编辑工具:Intellij IDEA 13.1

数据库: MYSQL 5.6

ps:使用IDEA导出了一份eclipse的配置。但是不知道能不能用eclipse打开。。未测试

类库依赖:

BoneCp 0.8.0

Mybatis 3.2.7

Mybatis-Spring 1.2.2

SpringFramework 3.2.10

Mysql-Connecter-java 3.1.31

ps:所有的依赖全部都是依靠Maven的。所以你懂的。

Main就是实例的测试代码。beans.xml配置文件里面的各个数据源的访问地址,账户和密码。自行修改

示例源代码下载地址:示例-基于Spring框架的简单多数据源切换解决办法

作者:TinyZ
出处:http://www.cnblogs.com/zou90512/
关于作者:努力学习,天天向上。不断探索学习,提升自身价值。记录经验分享。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接
如有问题,可以通过 zou90512@126.com 联系我,非常感谢。
笔者网店: http://aoleitaisen.taobao.com. 欢迎广大读者围观

基于Spring框架的简单多数据源切换解决办法的更多相关文章

  1. 基于Spring框架应用的权限控制系统的研究和实现

    摘 要: Spring框架是一个优秀的多层J2EE系统框架,Spring本身没有提供对系统的安全性支持.Acegi是基于Spring IOC 和 AOP机制实现的一个安全框架.本文探讨了Acegi安全 ...

  2. 基于ThinkPHP框架的简单的后台管理系统

    版权声明:本文为博主原创文章,未经博主允许不得转载. 基于ThinkPHP框架的简单的后台管理系统 一个简单的后台管理系统,可能还不全面,可以自己改,有登录功能 实例如图:    

  3. Eclipse IDE下的Spring框架使用简单实例

    Eclipse IDE下的Spring框架使用简单实例 1 准备Java jdk安装. Eclipse软件安装.根据系统安装32/64版本,选择Eclipse IDE for Java Develop ...

  4. 在vue中使用 layui框架中的form.render()无效解决办法

    下面简单介绍在vue中使用 layui框架中的form.render()无效解决办法. 原文地址:小时刻个人技术博客 > http://small.aiweimeng.top/index.php ...

  5. 第一次玩博客,今天被安利了一个很方便JDBC的基于Spring框架的一个叫SimpleInsert的类,现在就来简单介绍一下

    首先先对这段代码的简单介绍,我之前在需要操作JDBC的时候总是会因为经常要重新写SQL语句感到很麻烦.所以就能拿则拿不能拿的就简单地封装了一下. 首先是Insert.Spring框架的JDBC包里面的 ...

  6. 30个类手写Spring核心原理之动态数据源切换(8)

    本文节选自<Spring 5核心原理> 阅读本文之前,请先阅读以下内容: 30个类手写Spring核心原理之自定义ORM(上)(6) 30个类手写Spring核心原理之自定义ORM(下)( ...

  7. 基于Spring框架怎么构建游戏玩法服务

    说明:本篇阐述的问题,是基于前面的游戏服务器架构设计的. 问题 众所周知,Spring最擅长的领域是无状态服务的构建,而游戏(尤其是玩法部分)是有状态的.以棋牌游戏为例,玩法服务里面大概涉及以下两类对 ...

  8. 【Spring】使用Spring的AbstractRoutingDataSource实现多数据源切换

    最近因为项目需要在做两个项目间数据同步的需求,具体是项目1的数据通过消息队列同步到项目2中,因为这个更新操作还涉及到更新多个库的数据,所以就需要多数据源切换的操作.下面就讲讲在Spring中如何进行数 ...

  9. 使用Spring的AbstractRoutingDataSource实现多数据源切换

    https://www.cnblogs.com/softidea/p/7127874.html?utm_source=itdadao&utm_medium=referral https://b ...

随机推荐

  1. nodejs vue SyntaxError:Block-scoped declarations (let,const,function,class) not yet supported

    下午在git上导入之前写的代码到本地环境,执行npm run dev报错. 在我之前的环境中是没有问题的,这个错误信息也没看懂是什么原因引起的, 猜测可能是nodejs版本太低,于是重新下载了一个wi ...

  2. 2017.12.11SimpleDateFormat的线程安全性讨论

    转载来自:http://blog.csdn.net/zxh87/article/details/19414885 1.结论 DateFormat和SimpleDateFormat都不是线程安全的.在多 ...

  3. Expression-Based Access Control

    Expression-Based Access Control Spring Security 3.0 introduced the ability to use Spring EL expressi ...

  4. 用Markdown写博客快速入门

    Markdown,简单来说,就是一种可以方便转换为HTML的带标记符号纯文本. 它是对我等键盘党的福音:我不用再费劲挪动鼠标去按加粗.设置段落了,用键盘输入所有文本,一气呵成. 最重要的是,cnblo ...

  5. HDU 5296 Annoying problem

    Annoying problem Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...

  6. js 终止 for 循环

    1.break语句会使运行的程序立刻退出包含在最内层的循环或者退出一个switch语句. 2.for循环如果是多层循环 可以将循环命名,跳出指定的循环. first://需要将循环命名 for(var ...

  7. MAC OS X Yosemite的PyQt4配置记录

    MAC OS X Yosemite的PyQt4配置记录 声明: 1)本报告由博客园bitpeach撰写,版权所有,免费转载,请注明出处,并请勿作商业用途. 2)若本文档内有侵权文字或图片等内容,请联系 ...

  8. E492: Not an editor command: ^M

    在windows下拷贝vimrc到Linux,运行vim命令后,出现错误 vim E492: Not an editor command: ^M 原因: linux的文件换行符为\n,但windows ...

  9. LaTex幻灯片制作

    头部声明是“幻灯片”: \documentclass{beamer} 其他: \documentclass{beamer}\usepackage{graphicx}\usepackage{epstop ...

  10. Linux修改时间的方法

    http://www.blogjava.net/itvincent/archive/2007/08/03/134242.html修改linux的时间可以使用date指令 在命令行输入: date 显示 ...