多数据源的应用场景:主要是数据库拆分后,怎样让多个数据库结合起来来达到业务需求。

SSM框架(Spring+SpringMVC+MyBatis(MyBatis-Plus))是目前最常用的,此次仍然是maven工程。

关于这个多数据源例子,我已经上传到我的github上,地址为:https://github.com/youcong1996/study_simple_demo.git

不过需要注意的是,分支为demo1,不是主分支,如图所示:

如果下面的示例,你们看不懂或者不能理解,可以git clone我的地址

在编程的世界里,简洁即完美。

如何实现多数据源?

一句话,三个类加xml配置即可达到这个目的。

一、编写三个类

AbstractDynamicDataSource.java

package com.blog.datasource;import java.util.Map;import javax.sql.DataSource;import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** 动态数据源父类* @create ll* @update * @updateDate */
public abstract class AbstractDynamicDataSource<T extends DataSource> extends AbstractRoutingDataSourceimplementsApplicationContextAware {/** 日志 */protected Logger logger = LoggerFactory.getLogger(getClass());/** 默认的数据源KEY */protected static final String DEFAULT_DATASOURCE_KEY = "defaultDataSource";/** 数据源KEY-VALUE键值对 */public Map<Object, Object> targetDataSources;/** spring容器上下文 */private static ApplicationContext ctx;public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {ctx = applicationContext;}public static ApplicationContext getApplicationContext() {return ctx;}public static Object getBean(String name) {return ctx.getBean(name);}/*** @param targetDataSources the targetDataSources to set*/public void setTargetDataSources(Map<Object, Object> targetDataSources) {this.targetDataSources = targetDataSources;super.setTargetDataSources(targetDataSources);// afterPropertiesSet()方法调用时用来将targetDataSources的属性写入resolvedDataSources中的super.afterPropertiesSet();}/*** 创建数据源* @param driverClassName 数据库驱动名称* @param url 连接地址* @param username 用户名* @param password 密码* @return 数据源{@link T}* @Author : ll. create at 2017年3月27日 下午2:44:34*/public abstract T createDataSource(String driverClassName, String url, String username,String password);/*** 设置系统当前使用的数据源* <p>数据源为空或者为0时,自动切换至默认数据源,即在配置文件中定义的默认数据源* @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey()*/@Overrideprotected Object determineCurrentLookupKey() {logger.info("【设置系统当前使用的数据源】");Map<String, Object> configMap = DBContextHolder.getDBType();logger.info("【当前数据源配置为:{}】", configMap);if (MapUtils.isEmpty(configMap)) {// 使用默认数据源return DEFAULT_DATASOURCE_KEY;}// 判断数据源是否需要初始化this.verifyAndInitDataSource();logger.info("【切换至数据源:{}】", configMap);return configMap.get(DBContextHolder.DATASOURCE_KEY);}/*** 判断数据源是否需要初始化* @Author : ll. create at 2017年3月27日 下午3:57:43*/private void verifyAndInitDataSource() {Map<String, Object> configMap = DBContextHolder.getDBType();Object obj = this.targetDataSources.get(configMap.get(DBContextHolder.DATASOURCE_KEY));if (obj != null) {return;}logger.info("【初始化数据源】");T datasource = this.createDataSource(configMap.get(DBContextHolder.DATASOURCE_DRIVER).toString(), configMap.get(DBContextHolder.DATASOURCE_URL).toString(),configMap.get(DBContextHolder.DATASOURCE_USERNAME).toString(),configMap.get(DBContextHolder.DATASOURCE_PASSWORD).toString());this.addTargetDataSource(configMap.get(DBContextHolder.DATASOURCE_KEY).toString(),datasource);}/*** 往数据源key-value键值对集合添加新的数据源* @param key 新的数据源键* @param dataSource 新的数据源*/private void addTargetDataSource(String key, T dataSource) {this.targetDataSources.put(key, dataSource);super.setTargetDataSources(this.targetDataSources);// afterPropertiesSet()方法调用时用来将targetDataSources的属性写入resolvedDataSources中的super.afterPropertiesSet();}}

DBContextHolder.java

package com.blog.datasource;import java.util.HashMap;
import java.util.Map;public class DBContextHolder {/** 数据源的KEY */public static final String DATASOURCE_KEY = "DATASOURCE_KEY";/** 数据源的URL */public static final String DATASOURCE_URL = "DATASOURCE_URL";/** 数据源的驱动 */public static final String DATASOURCE_DRIVER = "DATASOURCE_DRIVER";/** 数据源的用户名 */public static final String DATASOURCE_USERNAME = "DATASOURCE_USERNAME";/** 数据源的密码 */public static final String DATASOURCE_PASSWORD = "DATASOURCE_PASSWORD";private static final ThreadLocal<Map<String, Object>> contextHolder = new ThreadLocal<Map<String, Object>>();public static void setDBType(Map<String, Object> dataSourceConfigMap) {contextHolder.set(dataSourceConfigMap);}public static Map<String, Object> getDBType() {Map<String, Object> dataSourceConfigMap = contextHolder.get();if (dataSourceConfigMap == null) {dataSourceConfigMap = new HashMap<String, Object>();}return dataSourceConfigMap;}public static void clearDBType() {contextHolder.remove();}
}

DruidDynamicDataSource.java

package com.blog.datasource;import java.sql.SQLException;
import java.util.List;import org.apache.commons.lang3.StringUtils;import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.pool.DruidDataSource;/*** Druid数据源* @update * @updateDate */
public class DruidDynamicDataSource extends AbstractDynamicDataSource<DruidDataSource> {private boolean testWhileIdle = true;private boolean testOnBorrow = false;private boolean testOnReturn = false;// 是否打开连接泄露自动检测private boolean removeAbandoned = false;// 连接长时间没有使用,被认为发生泄露时长private long removeAbandonedTimeoutMillis = 300 * 1000;// 发生泄露时是否需要输出 log,建议在开启连接泄露检测时开启,方便排错private boolean logAbandoned = false;// 只要maxPoolPreparedStatementPerConnectionSize>0,poolPreparedStatements就会被自动设定为true,使用oracle时可以设定此值。//    private int maxPoolPreparedStatementPerConnectionSize = -1;// 配置监控统计拦截的filtersprivate String filters; // 监控统计:"stat" 防SQL注入:"wall" 组合使用: "stat,wall"private List<Filter> filterList;/** 创建数据源* @see com.cdelabcare.pubservice.datasource.IDynamicDataSource#createDataSource(java.lang.String, java.lang.String, java.lang.String, java.lang.String)*/@Overridepublic DruidDataSource createDataSource(String driverClassName, String url, String username,String password) {DruidDataSource parent = (DruidDataSource) super.getApplicationContext().getBean(DEFAULT_DATASOURCE_KEY);DruidDataSource ds = new DruidDataSource();ds.setUrl(url);ds.setUsername(username);ds.setPassword(password);ds.setDriverClassName(driverClassName);ds.setInitialSize(parent.getInitialSize());ds.setMinIdle(parent.getMinIdle());ds.setMaxActive(parent.getMaxActive());ds.setMaxWait(parent.getMaxWait());ds.setTimeBetweenConnectErrorMillis(parent.getTimeBetweenConnectErrorMillis());ds.setTimeBetweenEvictionRunsMillis(parent.getTimeBetweenEvictionRunsMillis());ds.setMinEvictableIdleTimeMillis(parent.getMinEvictableIdleTimeMillis());ds.setValidationQuery(parent.getValidationQuery());ds.setTestWhileIdle(testWhileIdle);ds.setTestOnBorrow(testOnBorrow);ds.setTestOnReturn(testOnReturn);ds.setRemoveAbandoned(removeAbandoned);ds.setRemoveAbandonedTimeoutMillis(removeAbandonedTimeoutMillis);ds.setLogAbandoned(logAbandoned);// 只要maxPoolPreparedStatementPerConnectionSize>0,poolPreparedStatements就会被自动设定为true,参照druid的源码
        ds.setMaxPoolPreparedStatementPerConnectionSize(parent.getMaxPoolPreparedStatementPerConnectionSize());if (StringUtils.isNotBlank(filters))try {ds.setFilters(filters);} catch (SQLException e) {throw new RuntimeException(e);}addFilterList(ds);return ds;}private void addFilterList(DruidDataSource ds) {if (filterList != null) {List<Filter> targetList = ds.getProxyFilters();for (Filter add : filterList) {boolean found = false;for (Filter target : targetList) {if (add.getClass().equals(target.getClass())) {found = true;break;}}if (!found)targetList.add(add);}}}
}

二、修改配置文件

主要是修改spring-mybatis.xml

 <!-- 配置数据源 --><bean name="defaultDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><property name="url" value="${jdbc_url}"/><property name="username" value="${jdbc_username}"/><property name="password" value="${jdbc_password}"/><!-- 初始化连接大小 --><property name="initialSize" value="0"/><!-- 连接池最大使用连接数量 --><property name="maxActive" value="20"/><!-- 连接池最大空闲 --><property name="maxIdle" value="20"/><!-- 连接池最小空闲 --><property name="minIdle" value="0"/><!-- 获取连接最大等待时间 --><property name="maxWait" value="60000"/><property name="validationQuery" value="${validationQuery}"/><property name="testOnBorrow" value="false"/><property name="testOnReturn" value="false"/><property name="testWhileIdle" value="true"/><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --><property name="timeBetweenEvictionRunsMillis" value="60000"/><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --><property name="minEvictableIdleTimeMillis" value="25200000"/><!-- 打开removeAbandoned功能 --><property name="removeAbandoned" value="true"/><!-- 1800秒,也就是30分钟 --><property name="removeAbandonedTimeout" value="1800"/><!-- 关闭abanded连接时输出错误日志 --><property name="logAbandoned" value="true"/><!-- 监控数据库 --><property name="filters" value="mergeStat"/></bean><bean id="druidDynamicDataSource" class="com.blog.datasource.DruidDynamicDataSource"><property name="defaultTargetDataSource" ref="defaultDataSource" /><property name="targetDataSources"><map><entry key="defaultDataSource" value-ref="defaultDataSource"/><!-- 这里还可以加多个dataSource --></map></property></bean> <!-- Spring整合Mybatis,更多查看文档:http://mp.baomidou.com --><bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean"><property name="dataSource" ref="druidDynamicDataSource" /><!-- 自动扫描Mapping.xml文件 --><property name="mapperLocations" value="classpath:mybatis/system/*.xml"/><property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/><property name="typeAliasesPackage" value="com.blog.entity"/><property name="plugins"><array><!-- 分页插件配置 --><bean id="paginationInterceptor" class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean></array></property><!-- 全局配置注入 --><property name="globalConfig" ref="globalConfig" /></bean><!-- 配置事务管理 --><bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="druidDynamicDataSource"/></bean>

三、单元测试

import java.util.HashMap;
import java.util.List;
import java.util.Map;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.blog.datasource.DBContextHolder;
import com.blog.entity.User;
import com.blog.mapper.PostDao;
import com.blog.service.UserService;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring/spring.xml")
public class BlogTest {@Autowiredprivate UserService ud;@Testpublic void testName() throws Exception {Map<String, Object> map = new HashMap<String, Object>();map.put(DBContextHolder.DATASOURCE_KEY, "localhost");map.put(DBContextHolder.DATASOURCE_DRIVER, "com.mysql.jdbc.Driver");map.put(DBContextHolder.DATASOURCE_URL,"jdbc:mysql://127.0.0.1:3306/blog_test?useUnicode=true&characterEncoding=UTF-8");map.put(DBContextHolder.DATASOURCE_USERNAME, "root");map.put(DBContextHolder.DATASOURCE_PASSWORD, "1234");DBContextHolder.setDBType(map);List<User> list = ud.selectList(null);for (User user : list) {System.out.println(user);}}}

测试后,控制台如图:

小结:

其实配置多数据源有很多方式,有aop,也有配置多个bean的方式,当然了,只要能达到目的就是王道,当然了,我也强调一点,不是实现完就不管了,背后的为什么比只要实现就好更重要。

其实,有一点我想说的是,有些时候遇到难题,最好的方式是迎面而上解决这个问题,而不是逃避或者独自焦躁。同时直面问题,也是解决焦躁的最好方式。这个我已经深有体会了。

另外补充到,上传至github上的多数据源示例同时也是ssm框架的搭建。有哪位朋友不会搭建框架,可以参考我的这个。希望能对你们有什么帮助。

转载于:https://www.cnblogs.com/youcong/p/9806848.html

SSM框架之多数据源配置相关推荐

  1. SSM框架下log4j的配置和使用

    2019独角兽企业重金招聘Python工程师标准>>> 一.引入相关包和依赖 我用的是pom文件的引入,我使用的是slf4j+log4j的方式,还有另一种方式为commons-log ...

  2. 基于SSM框架社交媒体实现

    本文由本人的本科毕业论文修改而来,并不是论文的完整篇幅,部分已进行修改或删除.注意,在参考时还请注意查重等其他因素,由此所产生的相关问题均与本人无关,概不负责. 目录 摘要 Abstract 第一章 ...

  3. Java SSM框架后台搭建

    IDEA下载和激活 SpringBoot构建SSM框架 配置端口和数据库 运行项目 解决端口冲突 编译产物Jar 一.IDEA下载和激活 下载 Intelij IDEA商业版.商业版有很多Spring ...

  4. ssm框架mysql配置_ssm框架使用详解配置两个数据源

    学习ssm框架已经快一年了,今天把这个框架总结一下. SSM 就是指 spring.SpringMVC和Mybatis.先说一下基本概念(百度上搜的) 1.基本概念 1.1.Spring Spring ...

  5. 【重温SSM框架系列】2 - Spring配置数据源连接池(手动创建与配置)

    Spring配置数据源) 数据源(连接池概述) 自定义数据源(手动创建) 1. 导入Druid和mysql数据库驱动依赖包 2. 创建数据源对象并配置基本连接信息 使用JDBC操作数据库,打印user ...

  6. 搭建eclipse版的ssm+maven+tk.mybatis+redis及mybatis+spring多数据源配置集成的demo

    前言:我这里搭建好eclipse版的ssm+maven+tk.mybatis+redis及mybatis+spring多数据源配置集成的demo.新手快速上手直接看demo. 最后处提供完整高质量de ...

  7. 学校作业——配置ssm框架做一个简单的登陆注册

    补一下blog 1.配置maven 指向阿里的镜像并且导入ssm框架所需的依赖 <mirror><id>nexus-aliyun</id><mirrorOf& ...

  8. SSM框架整合+配置

    SSM框架整合 一. 框架简介及特征 1.SpringMVC springmvc是spring的一个模块,一个"小弟",用于web开发,可理解为servlet的升级版.Spring ...

  9. Eclipse配置SSM框架(非maven模式)

    1.创项目Dynamic web project 导入ssm框架所需的几十个jar包.导入lib目录下 需要注意,创建项目时一定要勾选生成web.xml 2.集成spring框架到项目之中 在src目 ...

最新文章

  1. ​数据集拥有自己的世界观?不,其实还是人的世界观
  2. OpenMP入门教程
  3. 网络:HTTP状态码
  4. 除了分析引擎 2.0,神策再发一波儿新功能!
  5. 在Linux系统安装Nodejs
  6. 如何把通达信公式变成python_通达信附图如何改成选股公式?
  7. keepalived VS zookeeper
  8. Git笔记(25) 选择修订版本
  9. 译:用iPhone SDK来画饼图(Pie Charts)报表
  10. NYOJ 90整数划分
  11. Couldn‘t find ffmpeg or avconv - defaulting to ffmpeg, but may not work
  12. 手把手带你可视化分析NBA首轮球队表现及火勇对决前瞻!
  13. python入门(三)--文件处理
  14. C语言通过for循环控制计时,C语言中关于时间的函数
  15. mac系统共享服务器,mac 链接共享服务器
  16. uarl 1019 涂色
  17. 苦尽甘来 一个月学通JavaWeb(三十五 数据库)
  18. 甘特图(Gantt Chart)绘制方法
  19. Zen Cart 插件
  20. 1800个python词汇_基本 Python 词汇

热门文章

  1. android开发——手机通话功能实现
  2. ospf多区域路由实验
  3. 某交规模拟考试系统验证绕路手记
  4. WindowsXP操作系统进程详细介绍
  5. Web前端笔记(6)
  6. 我的世界服务器的交易系统,我的世界村民交易系统详解_我的世界交易系统介绍_牛游戏网...
  7. oracle sql不用distinct去除重复,oracle sql 去重复记录不用distinct如何实现
  8. MySQL分组查询语句
  9. clean,compile,build,install,package区别
  10. Ribbon Finance将WBTC Theta Vault存款上限提高至250WBTC