Spring Boot实现多数据源快速入门

1.为什么需要多数据源?

多数据源既动态数据源,项目开发逐渐扩大,单个数据源、单一数据源已经无法满足需求项目的支撑需求。本文采用dynamic-datasource-spring-boot-starter实现多数据源,

主要特性

  • 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
  • 支持数据库敏感配置信息 加密 ENC()。
  • 支持每个数据库独立初始化表结构schema和数据库database。
  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
  • 支持 自定义注解 ,需继承DS(3.2.0+)。
  • 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。
  • 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。
  • 提供 自定义数据源来源 方案(如全从数据库加载)。
  • 提供项目启动后 动态增加移除数据源 方案。
  • 提供Mybatis环境下的 纯读写分离 方案。
  • 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
  • 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
  • 提供 **基于seata的分布式事务方案。
  • 提供 本地多数据源事务方案

2.环境搭建

本文使用2个mysql作为数据源,表都是一样的结构

第一个数据库

docker run --name docker-mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql

第二个数据库

docker run --name docker-mysql-2 -e MYSQL_ROOT_PASSWORD=123456 -p 3307:3306 -d mysql

初始化数据

create database demo;
create table user_info
(
user_id     varchar(64)          not null primary key,
username    varchar(100)         null ,
age         int(3)               null ,
gender      tinyint(1)           null ,
remark      varchar(255)         null ,
create_time datetime             null ,
create_id   varchar(64)          null ,
update_time datetime             null ,
update_id   varchar(64)          null ,
enabled     tinyint(1) default 1 null
);

 备注说明

msyql account:root
mysql password:123456

3.代码工程

实验目标:实现数据源的切换

 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-demo</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>dynamic-datasource</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- dynamic-datasource --><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.3.2</version></dependency><!-- mybatis-plus --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.3.1</version></dependency><!-- mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.10</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.3.1</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency></dependencies>
</project>

代码生成crud操作

package com.et.dynamic.datasource;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;public class GeneratorCode {/*** database connect* */private static final String dbUrl = "jdbc:mysql://localhost:3306/demo?useUnicode=true&useSSL=false&characterEncoding=utf8";/*** username* */private static final String username = "root";/*** pasword* */private static final String password = "123456";/*** moduleName* */private static final String moduleName = "/dynamic-datasource";/*** <p>* read console content* @param* </p>*/public static String scanner(String tip) {Scanner scanner = new Scanner(System.in);StringBuilder help = new StringBuilder();help.append("please input:" + tip + ":");System.out.println(help.toString());if (scanner.hasNext()) {String ipt = scanner.next();if (StringUtils.isNotBlank(ipt)) {return ipt;}}throw new MybatisPlusException("please right conntent:" + tip + "!");}public static void main(String[] args) {// Code GenerateorAutoGenerator mpg = new AutoGenerator();String module = scanner(" module");// GlobalCOnfigGlobalConfig gc = new GlobalConfig();//D:\IdeaProjects\ETFrameworkString basedir ="D:/IdeaProjects/ETFramework/";String projectPath = basedir+moduleName;System.out.println(projectPath);//OutputDirgc.setOutputDir(projectPath+"/src/main/java");gc.setAuthor("stopping");//some generate rulegc.setMapperName("%sMapper");gc.setServiceName("%sService");gc.setServiceImplName("%sServiceImp");gc.setControllerName("%sController");gc.setXmlName("%sMapper");gc.setIdType(IdType.AUTO);gc.setOpen(false);//IsOverridegc.setFileOverride(true);//isSwagger2gc.setSwagger2(false);mpg.setGlobalConfig(gc);//datasourceDataSourceConfig dsc = new DataSourceConfig();dsc.setUrl(dbUrl);dsc.setDriverName("com.mysql.cj.jdbc.Driver");dsc.setUsername(username);dsc.setPassword(password);mpg.setDataSource(dsc);// PackageConfigPackageConfig pc = new PackageConfig();//package pathpc.setParent("com.et.dynamic.datasource");//subpackage pathpc.setMapper("mapper."+module);pc.setController("controller."+module);pc.setService("service."+module);pc.setServiceImpl("service."+module+".imp");pc.setEntity("model.entity");pc.setXml("Mapper");mpg.setPackageInfo(pc);//custom configInjectionConfig cfg = new InjectionConfig() {@Overridepublic void initMap() {// to do nothing}};//  freemarkerString templatePath = "/templates/mapper.xml.ftl";// FileOutConfigList<FileOutConfig> focList = new ArrayList<>();focList.add(new FileOutConfig(templatePath) {@Overridepublic String outputFile(TableInfo tableInfo) {// MapperString xmlUrl = projectPath + "/src/main/resources/mapper/" + module+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;System.out.println("xml path:"+xmlUrl);return xmlUrl;}});cfg.setFileOutConfigList(focList);mpg.setCfg(cfg);// templateConfigTemplateConfig templateConfig = new TemplateConfig();templateConfig.setXml(null);mpg.setTemplate(templateConfig);// StrategyConfigStrategyConfig strategy = new StrategyConfig();strategy.setNaming(NamingStrategy.underline_to_camel);strategy.setColumnNaming(NamingStrategy.underline_to_camel);strategy.setEntityLombokModel(true);strategy.setRestControllerStyle(true);// common file//strategy.setSuperEntityColumns("id");strategy.setInclude(scanner("tablename,multi can be seperated ,").split(","));strategy.setControllerMappingHyphenStyle(true);strategy.setTablePrefix(pc.getModuleName() + "_");//isAnnotationEnablestrategy.setEntityTableFieldAnnotationEnable(true);mpg.setStrategy(strategy);mpg.setTemplateEngine(new FreemarkerTemplateEngine());mpg.execute();}
}

生成代码如下

1

然后修改service,增加切换数据源注解@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。 

注解结果
没有@DS默认数据源
@DS("dsName")dsName可以为组名也可以为具体某个库的名称
package com.et.dynamic.datasource.service.userinfo.imp;import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.et.dynamic.datasource.model.entity.UserInfo;
import com.et.dynamic.datasource.mapper.userinfo.UserInfoMapper;
import com.et.dynamic.datasource.service.userinfo.UserInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.List;/*** @author stopping* @since 2024-05-13*/
@Service
@DS("slave_1")
public class UserInfoServiceImp extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {@ResourceUserInfoMapper userInfoMapper;@Override@DS("master")public List<UserInfo> testQueryWrapper(int age) {QueryWrapper<UserInfo> userQueryWrapper = new QueryWrapper<>();userQueryWrapper.ge("age", age);List<UserInfo> userList = userInfoMapper.selectList(userQueryWrapper);return userList;}
}

application.yaml

配置下格式支持这几种

# 多主多从                      纯粹多库(记得设置primary)                   混合配置
spring:                               spring:                               spring:datasource:                           datasource:                           datasource:dynamic:                              dynamic:                              dynamic:datasource:                           datasource:                           datasource:master_1:                             mysql:                                master:master_2:                             oracle:                               slave_1:slave_1:                              sqlserver:                            slave_2:slave_2:                              postgresql:                           oracle_1:slave_3:                              h2:                                   oracle_2:

本文配置如下

   

server:port: 8088
spring:datasource:dynamic:primary: masterstrict: falsedatasource:master:url: jdbc:mysql://localhost:3306/demo?serverTimezone=Asia/Shanghaiusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverslave_1:url: jdbc:mysql://localhost:3307/demo?serverTimezone=Asia/Shanghaiusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver

4.测试

测试插入

@Test
public void insert()  {log.info("your method test Code");for(int i =1;i<10;i++) {UserInfo ui =  new UserInfo();ui.setUserId(i+"id");userInfoService.removeById(i+"id");ui.setUsername("HBLOG"+i);ui.setAge(i);userInfoService.save(ui);}

由于类上@DS("slave_1"),所以预期插入的slave_1mysql库。

测试查询

@Test
public void testQueryWrapper()  {log.info("your method test Code");userInfoService.testQueryWrapper(3).forEach(System.out::println);
}

查询方法注解的@DS("master"),所以在mater库上根本查不到数据

5.参考引用

  • 多数据源 | MyBatis-Plus
  • Spring Boot实现多数据源快速入门 | Harries Blog™

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/702258.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CheckStyle静态样式之道

优质博文&#xff1a;IT-BLOG-CN 在标准化的统一样式检查规范里&#xff0c;最为常用的统一样式工具是checkstyle插件&#xff0c;而不是国内阿里的代码规约插件。 【1】下载插件 【2】配置生效 配置生效及告警设置 【3】配置checkstyle.xml 官网地址 官网最新Releases 下面…

Node.js安装及环境配置(超详细!保姆级!!)

目录 一、进入官网地址下载安装包 二、安装程序 三、环境配置 四、测试 五、安装淘宝镜像 一、进入官网地址下载安装包 Node.js — Download Node.js (nodejs.org) 选择对应你系统的 node.js 版本&#xff0c;我选择的是Windows系统&#xff0c;64位 点击图中选项&#…

51单片机:点亮一个LED灯

1.新建工程 选择AT89C52&#xff0c;在Atmel下显示的是See Microchip 并不需要添加启动文件到文件夹中。 添加main.c文件&#xff0c;c比cpp效率高&#xff0c;.asm汇编即更底层 程序编写好后 nop(); 该函数在这个头文件里面 #include <INTRINS.H> #include <R…

ubuntu18.04 运行ur5机械臂

视觉抓取初探索1-UR5机械臂抓取仿真 - 知乎 抓取不止&#xff01;Ubuntu 18.04下UR5机械臂搭建Gazebo环境&#xff5c;开源分享_哔哩哔哩_bilibili 源码地址&#xff1a;GitHub - Geo-JTao/UR5_gripper_camera_gazebo: 在Ubantu18.04中搭建Gazebo仿真环境 遇到问题&#xff1…

Google Chrome 设备工具栏原理

1.不同预览模式 2.计算出缩放比 3.固定滚动偏移 关键代码&#xff1a; overview&#xff1a; ratioW getChildRect().width / getParentRect().width ratioH getChildRect().height / getParentRect().height maxRatio max(ratioW, ratioH) if(maxRatio < 1) return 1 …

21、G1分代回收究竟如何让传统方法黯然失色?

21.1、前文回顾 在上一篇文章中,我们详细解析了G1垃圾回收器的设计思想。其核心理念在于将内存分割为众多小的Region,并针对新生代和老年代各自分配一部分Region。在垃圾回收过程中,G1会优先挑选那些能实现最短停顿时间以及最多回收对象的Region,以尽可能确保达到预设的垃…

企业网站开发技术

随着互联网的快速发展&#xff0c;企业网站成为了企业宣传和推广的重要渠道之一。一个好的企业网站不仅可以提升企业的形象&#xff0c;还可以实现在线销售和客户服务等功能。那么&#xff0c;企业网站的开发技术有哪些呢&#xff1f;本文将从前端开发和后端开发两个方面进行讨…

InfluxDB学习之windows上安装inFluxDB

这里写目录标题 打开官网下载地址下载后解压如何启动&#xff1f;linux以及完整教程地址 打开官网下载地址 官网下载地址 如果出现注册提示&#xff0c;关闭掉就可以了&#xff0c;不用注册。下载地址就在下方。 下载后解压 解压后得到以下内容 如何启动&#xff1f; 我…

多点 Dmall x TiDB:出海多云多活架构下的 TiDB 运维实战

作者&#xff1a;多点&#xff0c;唐万民 导读 时隔 2 年&#xff0c; 在 TiDB 社区成都地区组织者冯光普老师的协助下&#xff0c;TiDB 社区线下地区活动再次来到成都。来自多点 Dmall 的国内数据库负责人唐万民老师&#xff0c;在《出海多云架构&#xff0c;多点 TiDB 运维…

Linux常用指令集合

ls显示目录文件 选项&#xff1a; -a 所有文件&#xff08;all所有&#xff09; -l 详细信息&#xff08;Information信息&#xff09;&#xff08;自动包含-1&#xff09; 所以常用 ll -1 一行只输出一个文件。 -R 列出所有子目录下的文件。…

Linux 服务器配置共享文件夹(NFS)

一、准备三台 linux 服务器 三台服务器: manger:172.16.11.178 ap1:172.16.11.179 ap2:172.16.11.180 /root/serverfiles/ 为共享目录 二、配置步骤 1、在服务端01的机器上安装nfs和rpcbind程序 yum -y install nfs* yum -y install rpcbind* 2、在安装完nfs以及rpcb…

Spring Boot:异常处理

Spring Boot 前言使用自定义错误页面处理异常使用 ExceptionHandler 注解处理异常使用 ControllerAdvice 注解处理异常使用配置类处理异常使用自定义类处理异常 前言 在 Spring Boot 中&#xff0c;异常处理是一个重要的部分&#xff0c;可以允许开发者优雅地处理应用程序中可…