spring boot+mybatis 多数据源切换实例讲解

  • 时间:
  • 845人关注

下面小编就为大家带来一篇spring boot+mybatis 多数据源切换(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,另外这篇文章主要知识点是关于springboot、mybatis、的内容,如果大家想对相关知识点有系统深入的学习,可以参阅以下电子资料:

由于公司业务划分了多个数据库,开发一个项目会同事调用多个库,经过学习我们采用了注解+aop的方式实现的

1.首先定义一个注解类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TargetDataSource {
 String value();//此处接收的是数据源的名称
}

2.然后建一个配置类,这个在项目启动时会加载数据源,一开始采用了HikariCP,查资料说是最快性能最好的,然后又发现了阿里的druid,这个功能比较全面,而且性能也还可以,最主要他还有监控功能,具体实现看如下代码

package com.example.demo.datasource;
 
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.example.demo.datasource.DynamicDataSource;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.PlatformTransactionManager;
import org.w3c.dom.NodeList;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
 
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.sql.DataSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.io.File;
import com.alibaba.druid.support.http.StatViewServlet;
/**
 * Author: wangchao
 * Version:
 * Date:  2017/9/11
 * Description:数据源配置
 * Modification History:
 * Date    Author    Version   Description
 * --------------------------------------------------------------
 * Why & What is modified:
 */
 
@Configuration
@EnableScheduling
public class DataSourceConfig {
 
 /*@Autowired
 private DBProperties properties;*/
 @Value("${datasource.filePath}")
 private String filePath;//数据源配置
 
 @Bean(name = "dataSource")
 public DataSource dataSource() {
  //按照目标数据源名称和目标数据源对象的映射存放在Map中
  Map<Object, Object> targetDataSources = new HashMap<>();
  //查找xml数据连接字符串
  targetDataSources=getdataMap(filePath);
  //动态获取DBProperties类申明的属性
  /*Field[] fields=properties.getClass().getDeclaredFields();
  for(int i=0;i<fields.length;i++)
  {
   targetDataSources.put(fields[i].getName(), getFieldValueByName(fields[i].getName(),properties));
  }*/
  //采用是想AbstractRoutingDataSource的对象包装多数据源
  DynamicDataSource dataSource = new DynamicDataSource();
  dataSource.setTargetDataSources(targetDataSources);
  //设置默认的数据源,当拿不到数据源时,使用此配置
  //dataSource.setDefaultTargetDataSource(properties.getUzaiTravel());
  return dataSource;
 }
 
 @Bean
 public PlatformTransactionManager txManager() {
  return new DataSourceTransactionManager(dataSource());
 }
 
 /**
 *获取数据源集合
 */
 
 private Map<Object, Object> getdataMap(String fiePath)
 {
 
  try {
   Map<Object, Object> targetDataSources = new HashMap<>();
   File xmlFile = new File(fiePath);
 
   DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
 
   DocumentBuilder builder = builderFactory.newDocumentBuilder();
 
   Document doc = builder.parse(xmlFile);
 
   doc.getDocumentElement().normalize();
 
   System.out.println("Root element: " + doc.getDocumentElement().getNodeName());
 
   NodeList nList = doc.getElementsByTagName("db");
   for(int i = 0 ; i<nList.getLength();i++) {
 
    Node node = nList.item(i);
    Element ele = (Element)node;
 
    /*HikariConfig config = new HikariConfig();
    config.setDriverClassName(ele.getElementsByTagName("driver-class").item(0).getTextContent());
    config.setJdbcUrl(ele.getElementsByTagName("jdbc-url").item(0).getTextContent());
    config.setUsername(ele.getElementsByTagName("username").item(0).getTextContent());
    config.setPassword(ele.getElementsByTagName("password").item(0).getTextContent());
    //config.addDataSourceProperty("password", ele.getElementsByTagName("password").item(0).getTextContent());
    HikariDataSource dataSource = new HikariDataSource(config);*/
 
 
    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName(ele.getElementsByTagName("driver-class").item(0).getTextContent());
    dataSource.setUsername(ele.getElementsByTagName("username").item(0).getTextContent());
    dataSource.setPassword(ele.getElementsByTagName("password").item(0).getTextContent());
    dataSource.setUrl(ele.getElementsByTagName("jdbc-url").item(0).getTextContent());
    dataSource.setInitialSize(5);
    dataSource.setMinIdle(1);
    dataSource.setMaxActive(10);// 启用监控统计功能
    dataSource.setFilters("stat");//设置是否显示sql语句
    targetDataSources.put(ele.getElementsByTagName("databasename").item(0).getTextContent(), dataSource);
   }
   return targetDataSources;
  }
  catch (Exception ex)
  {
   return null;
  }
 
 }
 //访问的ip
 @Value("${druid.IP}")
 private String IP;
 //登录名
 @Value("${druid.druidLgoinName}")
 private String druidLgoinName;
 //密码
 @Value("${druid.druidLgoinPassword}")
 private String druidLgoinPassword;
 
 @Bean
 public ServletRegistrationBean DruidStatViewServle() {
  //org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册.
  ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
  //添加初始化参数:initParams
 
  //白名单:
  servletRegistrationBean.addInitParameter("allow",IP);
  //IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
  // servletRegistrationBean.addInitParameter("deny", "192.168.1.73");
  //登录查看信息的账号密码.
  servletRegistrationBean.addInitParameter("loginUsername",druidLgoinName);
  servletRegistrationBean.addInitParameter("loginPassword",druidLgoinPassword);
  //是否能够重置数据.
  servletRegistrationBean.addInitParameter("resetEnable","false");
  return servletRegistrationBean;
 }
 
 /**
 
  * 注册一个:filterRegistrationBean
 
  * @return
 
 */
 @Bean
 public FilterRegistrationBean druidStatFilter2(){
  FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
  //添加过滤规则.
  filterRegistrationBean.addUrlPatterns("/*");
  //添加不需要忽略的格式信息.
  filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
  return filterRegistrationBean;
 }
 
}

3.动态数据源,从之前已加载的数据源中选取,DynamicDataSource和DynamicDataSourceHolder配合使用

public class DynamicDataSource extends AbstractRoutingDataSource{
 //数据源路由,此方用于产生要选取的数据源逻辑名称
 @Override
 protected Object determineCurrentLookupKey() {
  //从共享线程中获取数据源名称
  return DynamicDataSourceHolder.getDataSource();
 }
}

public class DynamicDataSourceHolder {
 /**
  * 本地线程共享对象
  */
 private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();
 
 public static void putDataSource(String name) {
  THREAD_LOCAL.set(name);
 }
 
 public static String getDataSource() {
  return THREAD_LOCAL.get();
 }
 
 public static void removeDataSource() {
  THREAD_LOCAL.remove();
 }
}

4.就是使用aop,在dao层切换数据源

@Component
@Aspect
public class DataSourceAspect {
 //切换放在mapper接口的方法上,所以这里要配置AOP切面的切入点
 @Pointcut("execution( * com.example.demo.dao.*.*(..))")
 public void dataSourcePointCut() {
 }
 
 @Before("dataSourcePointCut()")
 public void before(JoinPoint joinPoint) {
  Object target = joinPoint.getTarget();
  String method = joinPoint.getSignature().getName();
  Class<?>[] clazz = target.getClass().getInterfaces();
  Class<?>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
  try {
   Method m = clazz[0].getMethod(method, parameterTypes);
   //如果方法上存在切换数据源的注解,则根据注解内容进行数据源切换
   if (m != null && m.isAnnotationPresent(TargetDataSource.class)) {
    TargetDataSource data = m.getAnnotation(TargetDataSource.class);
    String dataSourceName = data.value();
    DynamicDataSourceHolder.putDataSource(dataSourceName);
 
   } else {
 
   }
  } catch (Exception e) {
 
  }
 }
 
 //执行完切面后,将线程共享中的数据源名称清空
 @After("dataSourcePointCut()")
 public void after(JoinPoint joinPoint){
  DynamicDataSourceHolder.removeDataSource();
 }
}

数据连接都配置在xml里面spring boot+mybatis 多数据源切换(实例讲解)

xml路径在配置文件里面配置,这样适用读写分离和多个不同的数据源,而且多个项目可以共用这一个配置

spring boot+mybatis 多数据源切换(实例讲解)

最后引用注解,需要注意的是注解的数据库名称和xml里面databasename节点是一一对应的,可以随便自定义,比如读写是一个数据库名字,这时候就可以定义成pringtest_r表示读库

spring boot+mybatis 多数据源切换(实例讲解)

至此多数据源就配置完成,至于阿里的druid下次再分享,代码都贴出来,如果大家感觉还有哪些不足的地方,欢迎指正。

以上这篇spring boot+mybatis 多数据源切换(实例讲解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持码农之家。


上一篇:实例分析Java Socket实现的传输对象功能

下一篇:Java程序运行机制及错误分析

相关内容

  • Springboot停止服务的方法总结

    这篇文章主要介绍了详解Springboot 优雅停止服务的几种方法 ,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    11-21详解Springboot优雅停止服务的几种方法

    阅读更多
  • Springboot+redis+Interceptor+自定义annotation实现接口自动幂等

    本篇文章给大家介绍了使用springboot和拦截器、redis来优雅的实现接口幂等,对于幂等在实际的开发过程中是十分重要的,因为一个接口可能会被无数的客户端调用,如何保证其不影响后台的业务

    04-26接口自动幂实现方法

    阅读更多
  • SpringBoot接口加密解密处理方法详解

    这篇文章主要为大家详细介绍了SpringBoot接口加密解密统一处理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    01-16SpringBoot接口加密解密统一处理

    阅读更多
  • Springboot项目与vue项目整合打包的实例操作方法

    这篇文章主要介绍了Springboot项目与vue项目整合打包的实现方式,本文通过两种方式给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

    07-07Springboot项目与vue项目整合打包的实现方式

    阅读更多
  • SpringBoot+Lucene实例介绍

    这篇文章主要介绍了详解SpringBoot+Lucene案例介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    07-16详解SpringBoot+Lucene案例介绍

    阅读更多
  • 疯狂Spring Cloud微服务架构实战

    疯狂Spring Cloud微服务架构实战

    《疯狂Spring Cloud微服务架构实战》以Spring Cloud为基础,深入讲解微服务开发的相关框架,包括服务管理框架Eureka、负载均衡框架Ribbon、服务客户端Feign、容错框架Hystrix、消息框架Stream等。

    大小:176.9 MB微服务

    点击下载
  • Spring Cloud微服务:全栈技术与案例解析

    Spring Cloud微服务:全栈技术与案例解析

    本书的读者对象主要是Java开发人员:特别是工作1到3年这种工作经验的开发人员,这个阶段的开发人员技术能力一般,正需要一些实用的技术和经验来提升自己,Spring Cloud正是

    大小:189.7 MB微服务

    点击下载
  • Spring技术内幕:深入解析Spring架构与设计

    Spring技术内幕:深入解析Spring架构与设计

    大小:53 MBSpring技术

    点击下载
  • Spring Cloud Finchley RELEASE 官方中英文档

    Spring Cloud Finchley RELEASE 官方中英文档

    这是一套Spring Cloud Finchley中文参考手册,内含有中文pdf和英文版pdf,中文文档都是由软件翻译,翻译内容未检查校对,文档内容仅供参考,需要的朋友可下载试试! Spring Cloud 是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将各家公司开发的比

    大小:8.88 MBSpring

    点击下载
  • Spring+MyBatis企业应用实战

    Spring+MyBatis企业应用实战

    Spring+MyBatis企业应用实战(第2版) 主要详细介绍了JavaEE行业的2个开源系统架构:Spring的MVC和MyBatis。在其中Spring的版本号为5.0,MyBatis的版本号是3.4.5。这书的实例提议在Tomcat8上运作。 这书重中之

    大小:111 MBSpring MVC 5

    点击下载
  • Spring Cloud与Docker微服务架构实战

    Spring Cloud与Docker微服务架构实战

    Spring Cloud与Docker微服务架构实战 可分为三部分,第1章对微服务架构进行了系统的介绍;第2-11章使用Spring Cloud开发框架编写了一个电影售票系统;第12-14章则讲解了如何将微服务应用运行在Do

    大小:100 MB微服务

    点击下载
  • 一步一步学Spring Boot 2

    一步一步学Spring Boot 2

    本书主要内容包括Spring Boot环境搭建、Spring Boot常用标签、Spring Boot集成Redis、数据库MySQL、Spring Data、日志Log4J、Thymeleaf模板引擎、ActiveMQ消息、MyBatis等流行技术,以及利用Spring Boot实现邮件发送、Quartz定时器、过滤器Filter和监听器Listener等。

    大小:72.04 MBSpring Boot

    点击下载
  • Spring MVC+MyBatis快速开发与项目实战

    Spring MVC+MyBatis快速开发与项目实战

    本书从开发实战出发,以新版Spring、Spring MVC和MyBatis为基础,结合开发工具Intellij IDEA,通过完整的项目实例让读者快速掌握SSM的开发技能。

    大小:179.1 MBspring

    点击下载
  • 精通Spring MVC4

    精通Spring MVC4

    在精通Spring MVC4中,我们将会从头开始构建一个有用的Web应用。从开发自己的Web应用开始, 到将其部署到云中,涉及处理文件上传和复杂的URL,保护和优化Spring Web应用等

    大小:11.3 MBSpring

    点击下载
  • Spring微服务实战

    Spring微服务实战

    本书教读者如何使用Java和Spring平台构建基于微服务的应用程序。在构建和部署Spring Cloud应用程序时,读者将学习如何进行微服务设计。精心挑选的真实案例展示了基于微服务的各种模式,这些模式用于配置、路由、扩展和部署服务。

    大小:215.7 MBSpring微服务

    点击下载

学习笔记

33小时53分钟前回答

Spring Boot日志控制代码实例

Spring Boot 对日志的处理,和我们平时的日志处理完全一致,通过 logback.xml 进行日志管理功能。为了简便,这里采用Spring Boot构建框架一章节使用的工程,讲述如何在Spring Boot中处理日志。 第一步 ,虽然Spring Boot中 application.properties 配置文件提供了日志的配置,但是个人更倾向于旧的配置方式。在src/main/resources目录中增加 logback.xml 日志文件,文件内容如下(配置相对简单,个人请根据工程情况,进行相应的配置): configuration scan=true scanPeriod=10 seconds include resource=org/springframework/boot/logging/logback/base.xml / appender name=INFO_FILE class=ch.qos.logback.core.rolling.RollingFileAppender File${LOG_PATH}/info.log/File rollingPolicy class=ch.qos……

1小时57分钟前回答

SpringBoot生产快速禁用Swagger2的具体方法

你还在生产节点开放Swagger吗,赶紧停止这种暴露接口的行为吧。 学习目标 快速学会使用注解关闭Swagger2,避免接口重复暴露。 使用教程 禁用方法1:使用注解 @Profile({dev,test}) 表示在开发或测试环境开启,而在生产关闭。(推荐使用) 禁用方法2:使用注解 @ConditionalOnProperty(name = swagger.enable, havingValue = true) 然后在测试配置或者开发配置中 添加 swagger.enable = true 即可开启,生产环境不填则默认关闭Swagger. 例如: /** * Swagger2 接口配置 */@Configuration@EnableSwagger2//@Profile({dev,test})@ConditionalOnProperty(name = swagger.enable, havingValue = true)public class Swagger2Config { /** * 添加摘要信息(Docket) */ @Bean public Docket controllerApi() { return……

20小时28分钟前回答

Springboot项目平滑关闭及自动化关闭脚本详解

Springboot项目平滑关闭及自动化关闭脚本,供大家参考,具体内容如下 核心代码 GracefulShutdown.java Shutdown.java ApplicationStarterRunner.java CommonInfo.java HttpCommonUtil.java application.properties 操作步骤 核心代码 GracefulShutdown.java package cnkj.site.utils;import org.apache.catalina.LifecycleException;import org.apache.catalina.connector.Connector;import org.apache.catalina.util.LifecycleBase;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;import org.springframework.context.ApplicationListener;im……

7小时23分钟前回答

Spring Boot中属性绑定的实现方法

之前翻译了一篇不怎么样的文章,主要是翻译的水平有限,自己翻译的云里雾里,发现平时只会有@ConfigurationProperties注解,对SpringBoot强大的属性绑定知之甚少,所以以那篇文章为线索,重新学习了一遍。 @ConfigurationProperties 在使用的时候,我们往往只关心两件事,属性怎么绑定,即属性文件中的值和配置类中字段的映射关系;其次是类实例化的时机。故而衍生开来ConfigurationProperties有三种用法。 @Component + @ConfigurationProperties 这种用法最简单,直接在POJO类上加上注解即可,Spring容器初始化时就会生成配置类实例了。适合POJO类是自定义的。 @Component@ConfigurationProperties(prefix = kaka.cream.mail-a,ignoreUnknownFields = ……

24小时42分钟前回答

spring-boot-starter-web更换默认Tomcat容器的步骤

Spring Boot支持容器的自动配置,默认是Tomcat,当然我们也是可以进行修改的。 我们知道Spring Boot支持容器的自动配置,默认是Tomcat,当然我们也是可以进行修改的: 1、首先我们排除spring-boot-starter-web依赖中的Tomcat:在pom文件中排除tomcat的starter dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId exclusions exclusion groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-tomcat/artifactId /exclusion /exclusions/dependency 2、加入Jetty容器 dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-jetty/artifactId/dependency 这样我们的springboot容器就修改成Jetty容器了。 为了方便我们的调试,这里给大家推荐……