我的编程空间,编程开发者的网络收藏夹
学习永远不晚

SpringBoot多数据源配置并通过注解实现动态切换数据源

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

SpringBoot多数据源配置并通过注解实现动态切换数据源

1. 环境准备

1.1 数据库准备

一个本地环境的MySQL数据库,数据库mydb,创建表t_user

CREATE TABLE `t_user` (
  `c_id` varchar(20) NOT NULL,
  `c_username` varchar(20) DEFAULT NULL,
  `c_password` varchar(20) DEFAULT NULL,
  `c_gender` tinyint(2) DEFAULT NULL,
  PRIMARY KEY (`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO `mydb`.`t_user`(`c_id`, `c_username`, `c_password`, `c_gender`) VALUES ('1', '思思', '123', 1);

一个云服务器的MySQL数据库,创建数据库book_db,创建表t_userinfo。

CREATE TABLE `t_user_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
  `password` varchar(255) DEFAULT NULL COMMENT '登录密码',
  `areaObj` varchar(255) DEFAULT NULL COMMENT '所在学院',
  `name` varchar(20) DEFAULT NULL COMMENT '姓名',
  `sex` tinyint(255) DEFAULT NULL COMMENT '性别',
  `user_photo` varchar(255) DEFAULT NULL COMMENT '学生照片',
  `birthday` varchar(20) DEFAULT NULL COMMENT '出生日期',
  `telephone` varchar(20) DEFAULT NULL COMMENT '联系电话',
  `address` varchar(255) DEFAULT NULL COMMENT '家庭地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

INSERT INTO `book_db`.`t_user_info`(`id`, `user_name`, `password`, `areaObj`, `name`, `sex`, `user_photo`, `birthday`, `telephone`, `address`) VALUES (1, '张三', '123', '哈尔滨', '张三散', 1, '123', '02-16', '15756892458', '黑龙江省哈尔滨市');

创建数据库chatroom,创建表admin。

CREATE TABLE `admin` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) NOT NULL COMMENT '登录账号',
  `nickname` varchar(20) NOT NULL COMMENT '昵称',
  `password` varchar(255) NOT NULL COMMENT '密码',
  `user_profile` varchar(255) DEFAULT NULL COMMENT '管理员头像',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

INSERT INTO `chatroom`.`admin`(`id`, `username`, `nickname`, `password`, `user_profile`) VALUES (1, 'admin', '系统管理员', '$2a$10$PyloUEVGuO0fUZdfeIaROOTluRmccl.Scifa8S7Os0Wt.s4bDkb', 'https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1784117537,3335593911&fm=26&gp=0.jpg');

1.2 项目创建

创建SpringBoot项目,整合MyBatis-Plus。pom.xml引入的依赖:

<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>

		<!--mybatis plus-->
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.0.1</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!--druid-->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.10</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.9</version>
		</dependency>

	</dependencies>

配置读取resource文件夹下的mapper文件

	<build>
		<resources>
			<resource>
				<directory>class="lazy" data-src/main/java</directory>
				<includes>
					<include>**
    CHATROOM("chatroom"),
    
    BOOK_DB("book_db"),
    
    MY_DB("mydb");

    private final String name;

    DataSourceTypeEnum(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

4.2 创建动态多数据源类

定义一个动态多数据源类DynamicDataSource用于管理不同线程间多个数据源的选择和切换,扩展 Spring 提供的 AbstractRoutingDataSource 抽象类,重写 determineCurrentLookupKey 方法,其中的determineCurrentLookupKey() 方法用于决定使用哪个数据源。

public class DynamicDataSource extends AbstractRoutingDataSource {

    
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    
    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    
    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

    public static void setDataSource(String dataSource) {
        CONTEXT_HOLDER.set(dataSource);
    }

    public static String getDataSource() {
        return CONTEXT_HOLDER.get();
    }
    
    public static void clearDataSource() {
        CONTEXT_HOLDER.remove();
    }
}

4.3 创建动态多数据源配置类

DynamicDataSourceConfig类作为配置类,读取配置文件的三个数据源的配置,创建对应DataSource类型的Bean。

@Configuration
public class DynamicDataSourceConfig {

    @Bean(name="chatroom")
    @ConfigurationProperties("spring.datasource.druid.first")
    public DataSource dataSource1(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name ="book_db")
    @ConfigurationProperties("spring.datasource.druid.second")
    public DataSource dataSource2(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name="mydb")
    @ConfigurationProperties("spring.datasource.druid.third")
    public DataSource dataSource3(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name="dynamicDataSource")
    @Primary
    public DynamicDataSource dataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>(5);
        targetDataSources.put(DataSourceTypeEnum.CHATROOM.getName(), dataSource1());
        targetDataSources.put(DataSourceTypeEnum.BOOK_DB.getName(), dataSource2());
        targetDataSources.put(DataSourceTypeEnum.MY_DB.getName(), dataSource3());
        return new DynamicDataSource(dataSource1(), targetDataSources);
    }
}

4.4 自定义注解用于指定数据源

自定义注解@SpecifyDataSource用于在Service层方法上标记要使用哪个数据源。这里定义默认使用数据源 DataSourceType.CHATROOM。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SpecifyDataSource {

    
    DataSourceTypeEnum value() default DataSourceTypeEnum.CHATROOM;
}

4.5 AOP实现动态切换数据源

定义数据源界面类DataSourceAspect,用于实现有SpecifyDataSource注解标注的方法前切换注解指定的数据源。

@Aspect
@Component
@Order(value = 1)
public class DataSourceAspect {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Pointcut("@annotation(top.javahai.datasource.annotation.SpecifyDataSource)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();

        SpecifyDataSource ds = method.getAnnotation(SpecifyDataSource.class);
        if (ds == null) {
            DynamicDataSource.setDataSource(DataSourceType.CHATROOM.getName());
            logger.info("set datasource is " + DataSourceType.CHATROOM);
        } else {
            DynamicDataSource.setDataSource(ds.value().getName());
            logger.info("set datasource is " + ds.value().getName());
        }

        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            logger.info("clean datasource");
        }
    }
}

5. 测试使用

5.1 配置数据源

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
# 数据源1
spring.datasource.druid.first.url=jdbc:mysql://158.156.444.68:3306/chatroom?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.first.username=root
spring.datasource.druid.first.password=123456
# 数据源2
spring.datasource.druid.second.url=jdbc:mysql://158.156.444.68:3306/book_db?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.second.username=root
spring.datasource.druid.second.password=123456

#数据源3
spring.datasource.druid.third.url=jdbc:mysql:///mydb?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.third.username=root
spring.datasource.druid.third.password=123456

mybatis-plus.mapper-locations=classpath:mapper
    private String username;

    
    private String nickname;

    
    private String password;

    
    private String userProfile;

//省略getter/setter方法

创建实体类TUser

public class TUser implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "c_id", type = IdType.AUTO)
    private Integer cId;

    private String cUsername;

    private String cPassword;

    private Integer cGender;
}

创建实体类TUserinfo

@TableName(value = "t_user_info")
public class TUserinfo implements Serializable {

    private static final long serialVersionUID = 1L;

    
    private String userName;

    
    private String password;

    
    @TableField("areaObj")
    private String areaObj;

    
    private String name;

    
    private Integer sex;

    
    private String userPhoto;

    
    private String birthday;

    
    private String telephone;

    
    private String address;
}

创建UserVO用于测试

public class UserVO {

    private List<Admin> adminList;
    private List<TUserinfo> tUserinfos;
    private List<TUser> tUsers;
}

5.3 服务层代码

@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {

    public List<Admin> getAll(){
        return this.list(null);
    }
}
@Service
public class TUserinfoServiceImpl extends ServiceImpl<TUserinfoMapper, TUserinfo> implements ITUserinfoService {

    @SpecifyDataSource(value = DataSourceTypeEnum.BOOK_DB)
    public List<TUserinfo> selectAll(){
        return this.list(null);
    }

}
@Service
public class TUserServiceImpl extends ServiceImpl<TUserMapper, TUser> implements ITUserService {

    @SpecifyDataSource(value = DataSourceTypeEnum.MY_DB)
    public List<TUser> selectAll(){
        return this.list(null);
    }
}
public interface AdminMapper extends BaseMapper<Admin> {

}

public interface TUserinfoMapper extends BaseMapper<TUserinfo> {

}

public interface TUserMapper extends BaseMapper<TUser> {

}

5.4 控制层代码

创建接口/test/list用于测试

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private AdminServiceImpl adminService;

    @Autowired
    private TUserinfoServiceImpl userinfoService;

    @Autowired
    private TUserServiceImpl userService;

    @GetMapping("/list")
    public UserVO list(){
        List<Admin> adminList= adminService.getAll();
        List<TUserinfo> tUserinfos = userinfoService.selectAll();
        List<TUser> tUsers = userService.selectAll();
        UserVO userVO = new UserVO();
        userVO.setAdminList(adminList);
        userVO.settUserinfos(tUserinfos);
        userVO.settUsers(tUsers);
        return userVO;
    }
}

浏览器请求/test/list

在这里插入图片描述

查看控制台输出,查看数据源的切换日志

,

完整Demo代码地址:https://github.com/JustCoding-Hai/learn-everyday/tree/master/learn-multi_data_source

到此这篇关于SpringBoot多数据源配置并通过注解实现动态切换数据源的文章就介绍到这了,更多相关SpringBoot 动态切换数据源内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

SpringBoot多数据源配置并通过注解实现动态切换数据源

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SpringBoot多数据源配置并通过注解实现动态切换数据源

本文主要介绍了SpringBoot多数据源配置并通过注解实现动态切换数据源,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2022-11-13

Springboot动态切换数据源怎么实现

这篇文章主要介绍“Springboot动态切换数据源怎么实现”,在日常操作中,相信很多人在Springboot动态切换数据源怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Springboot动态切换数
2023-06-25

【Java多数据源实现教程】实现动态数据源、多数据源切换方式

前言 本文为 【Java多数据源实现教程】 相关知识,由于自己最近在做导师的项目的时候需要使用这种技术,于是自学了相关技术原理与实现,并将其整理如下,具体包含:多数据源的典型使用场景(包含业务复杂场景、读写分离场景),多数据源实现原理及实
2023-08-16

SpringBoot+Mybatis如何实现动态数据源切换

这篇文章主要介绍了SpringBoot+Mybatis如何实现动态数据源切换,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。springboot是什么springboot一种全
2023-06-14

SpringBoot基于AbstractRoutingDataSource如何实现多数据源动态切换

本文小编为大家详细介绍“SpringBoot基于AbstractRoutingDataSource如何实现多数据源动态切换”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringBoot基于AbstractRoutingDataSour
2023-06-30

SpringBoot多数据源切换怎么实现

本篇内容主要讲解“SpringBoot多数据源切换怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“SpringBoot多数据源切换怎么实现”吧!配置文件(YML)spring: data
2023-06-30

Spring多数据源AOP动态切换怎么实现

这篇文章主要讲解了“Spring多数据源AOP动态切换怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring多数据源AOP动态切换怎么实现”吧!一:新增多数据源类public c
2023-06-04

springboot+dynamicDataSource怎么实现动态添加切换数据源

今天小编给大家分享一下springboot+dynamicDataSource怎么实现动态添加切换数据源的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,
2023-06-26

SpringBoot怎么实现多数据源的切换

这篇文章主要介绍“SpringBoot怎么实现多数据源的切换”,在日常操作中,相信很多人在SpringBoot怎么实现多数据源的切换问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”SpringBoot怎么实现多
2023-06-29

Java注解实现动态数据源切换的实例代码

当一个项目中有多个数据源(也可以是主从库)的时候,我们可以利用注解在mapper接口上标注数据源,从而来实现多个数据源在运行时的动态切换。实现原理在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充
2023-05-31

java动态数据源切换怎么实现

在Java中实现动态数据源切换有多种方式,以下是其中一种常见的实现方法:1. 创建一个数据源容器类:创建一个类来管理多个数据源对象,例如一个Map,使用数据源名称作为键,数据源对象作为值。2. 创建注
2023-10-09

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录