百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 文章教程 > 正文

SpringBoot实现动态数据源配置 springboot 动态数据源

xsobi 2024-12-15 17:31 1 浏览

本文将会介绍SpringBoot集成Mybatis,主要关注DataSource的配置

然后引入Druid数据库连接池,最后使用Zookeeper实现数据源的动态配置

3.1.SpringBoot集成Mybatis

3.1.1.添加依赖包

添加项目依赖包;SpringBoot、Mybatis、Mysql连接等

<?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>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.12.RELEASE</version>
        <relativePath/>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.poiuy</groupId>
    <version>1.0-SNAPSHOT</version>
    <artifactId>springboot-datasource-mybatis</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.12.RELEASE</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
            <version>2.5.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-typehandlers-jsr310</artifactId>
            <version>1.0.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>2.3.11.RELEASE</version>
        </dependency>
    </dependencies>
</project>

3.1.2.添加SpringBoot配置文件

SpringBoot配置文件,添加datasource和mybatis的配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: xxx
    url: jdbc:mysql://192.168.1.208:9906/poiuy_study?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: org.poiuy.springboot.datasource.mybatis.domain

3.1.3.添加Domain类

添加数据对象

public class MybatisUser {
    private Integer userId;

    @NotNull(message = "用户名不能为空")
    private String username;
    private String secure;

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSecure() {
        return secure;
    }

    public void setSecure(String secure) {
        this.secure = secure;
    }
}

3.1.4.添加Mapper

mapper接口中添加一个查询用户方法

@Mapper
public interface MybatisUserMapper {
    MybatisUser selectByUsername(@Param("username") String username);
}

对应的xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="org.poiuy.springboot.datasource.mybatis.dao.MybatisUserMapper">
    <resultMap id="BaseResultMap" type="org.poiuy.springboot.datasource.mybatis.domain.MybatisUser">
        <id property="userId" column="user_id" jdbcType="INTEGER"/>
        <result property="username" column="username" jdbcType="VARCHAR"/>
        <result property="secure" column="secure" jdbcType="VARCHAR"/>
    </resultMap>

    <!--MybatisUserMapper select(@Param("name") String name);-->
    <select id="selectByUsername" resultMap="BaseResultMap">
        SELECT user_id,username FROM mybatis_user WHERE username = #{username}
    </select>
</mapper>

3.1.5.Service接口

service接口直接调用mapper方法

@Service("mybatisUserService")
public class MybatisUserServiceImpl implements MybatisUserService {
    private final MybatisUserMapper mybatisUserMapper;

    @Autowired
    public MybatisUserServiceImpl(MybatisUserMapper mybatisUserMapper) {
        this.mybatisUserMapper = mybatisUserMapper;
    }

    @Override
    public MybatisUser getUserByUsername(String username) {
        return mybatisUserMapper.selectByUsername(username);
    }
}

3.1.6.Controller控制器

user控制器

@RestController
@RequestMapping("/user")
public class UserController {
    private final Logger logger = LogManager.getLogger(getClass());
    private final MybatisUserService mybatisUserService;

    @Autowired
    public UserController(MybatisUserService mybatisUserService){
        this.mybatisUserService = mybatisUserService;
    }

    @PostMapping
    public R getByUsername(@RequestBody @Valid MybatisUser mybatisUser){
        String username = mybatisUser.getUsername();
        logger.debug("获取到参数:{}",username);
        MybatisUser dbUser = mybatisUserService.getUserByUsername(username);
        return R.ok().put("data",dbUser);
    }
}

3.1.7.测试

运行SpringBoot程序,在PostMan中调用请求

3.2.增加Druid连接池

3.2.1.添加依赖包

添加Druid的依赖包

<?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>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.12.RELEASE</version>
        <relativePath/>
    </parent>

    <modelVersion>4.0.0</modelVersion>

    <version>1.0-SNAPSHOT</version>
    <groupId>org.poiuy</groupId>
    <artifactId>springboot-datasource-druid</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.12.RELEASE</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
            <version>2.5.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.5</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>2.4.0</version>
        </dependency>
    </dependencies>

</project>

3.2.2.修改SpringBoot配置文件

SpringBoot配置文件,删除原来的Datasource配置,并增加Druid

Druid分为基础配置、监控配置和连接池参数配置。可根据需要进行配置

spring:
  datasource:
    # 切换数据源
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      # Druid基础配置 , 与DataSource配置等同的效果
      username: root
      password: xxx
      url: jdbc:mysql://192.168.1.208:9906/poiuy_study?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
      driver-class-name: com.mysql.cj.jdbc.Driver

      # Druid监控
      filter:
        stat:
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: false
        wall:
          config:
            multi-statement-allow: true
      web-stat-filter:
        enabled: true
        url-pattern: /*
        exclusions: /druid/*,*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico
        session-stat-enable: true
        session-stat-max-count: 10
        principal-session-name: session_name
        principal-cookie-name: cookie_name
        profile-enable:
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*
        reset-enable: false
        login-username: poiuy
        login-password: 123456
        allow: 127.0.0.1,192.168.1.111
        deny:
      aop-patterns:

      #连接池配置
      name: testDruidDataSource
      initial-size: 10
      max-active: 20
      min-idle: 10
      max-wait: 60000
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
      validation-query: SELECT 1 FROM DUAL
      validation-query-timeout: 3000
      test-on-borrow: false
      test-on-return: false
      test-while-idle: true
      time-between-eviction-runs-millis: 5000
      min-evictable-idle-time-millis: 5000
      max-evictable-idle-time-millis: 5000

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: org.poiuy.springboot.datasource.mybatis.domain

3.2.3.测试

运行SpringBoot程序,在PostMan中调用请求

另外如果配置了Druid监控配置项,那么在浏览器输入http://localhost:8080/druid/index.html

可以进入Druid的监控界面

3.3.Zookeeper实现数据源的动态配置

3.3.1.添加依赖包

在pom.xml中新增curator依赖包

<?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>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.12.RELEASE</version>
        <relativePath/>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.poiuy</groupId>
    <version>1.0-SNAPSHOT</version>
    <artifactId>springboot-datasource-dynamic</artifactId>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.12.RELEASE</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
            <version>2.5.2</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.5</version>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.11.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>2.3.12.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.8</version>
        </dependency>
    </dependencies>
</project>

3.3.2.SpringBoot配置文件

修改SpringBoot配置文件,将Druid的基础配置进行注释,并添加Zookeeper配置项

spring:
  datasource:
    # 切换数据源
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      # Druid基础配置 , 与DataSource配置等同的效果
      # username: root
      # password: xxx
      # url: jdbc:mysql://192.168.1.208:9906/poiuy_study?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
      # driver-class-name: com.mysql.cj.jdbc.Driver

      # Druid监控
      filter:
        stat:
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: false
        wall:
          config:
            multi-statement-allow: true
      web-stat-filter:
        enabled: true
        url-pattern: /*
        exclusions: /druid/*,*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico
        session-stat-enable: true
        session-stat-max-count: 10
        principal-session-name: session_name
        principal-cookie-name: cookie_name
        profile-enable:
      stat-view-servlet:
        enabled: true
        url-pattern: /druid/*
        reset-enable: false
        login-username: poiuy
        login-password: 123456
        allow: 127.0.0.1,192.168.1.111
        deny:
      aop-patterns:

      #连接池配置
      name: testDruidDataSource
      initial-size: 10
      max-active: 20
      min-idle: 10
      max-wait: 60000
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
      validation-query: SELECT 1 FROM DUAL
      validation-query-timeout: 3000
      test-on-borrow: false
      test-on-return: false
      test-while-idle: true
      time-between-eviction-runs-millis: 5000
      min-evictable-idle-time-millis: 5000
      max-evictable-idle-time-millis: 5000

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: org.poiuy.springboot.datasource.mybatis.domain

zookeeper:
  connectString: 192.168.1.208:2181
  connectionTimeoutMs: 5000
  maxRetries: 3
  baseSleepTimeMs: 1000
  listenerPath: /zookeeper/datasource

3.3.3.集成Zookeeper

创建ZookeeperConfig,将CuratorFramework注入到Spring中,用来操作Zookeeper

@Configuration
public class ZookeeperConfig {
    @Value("${zookeeper.connectString}")
    private String connectString;
    @Value("${zookeeper.connectionTimeoutMs}")
    private Integer connectionTimeoutMs;
    @Value("${zookeeper.maxRetries}")
    private Integer maxRetries;
    @Value("${zookeeper.baseSleepTimeMs}")
    private Integer baseSleepTimeMs;

    private CuratorFramework client;

    @PostConstruct
    public void init(){
        client = CuratorFrameworkFactory.builder()
                .connectString(connectString)
                .connectionTimeoutMs(connectionTimeoutMs)
                .retryPolicy(new ExponentialBackoffRetry(baseSleepTimeMs, maxRetries))
                .build();
        //连接
        client.start();
    }

    @Bean
    public CuratorFramework curatorFramework(){
        return this.client;
    }
}

3.3.4.定义DataSource配置

此时需要重新构建DruidDataSource对象,在生成dataSource时从zookeeper中获取配置信息,并赋值到DataSource

这里只写了基本的4个参数,注意此时需要将Spring配置文件中相同的属性删除,否则会被Spring配置文件中的值覆盖掉

@Configuration
public class DruidConfig {
    private final Logger logger = LogManager.getLogger(getClass());

    @Resource
    private CuratorFramework curatorFramework;

    @Value("${zookeeper.listenerPath}")
    private String datasourceParh;

    @ConfigurationProperties(prefix = "spring.datasource.druid")
    @Bean
    public DataSource dataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();

        try {
            byte[] datasourceData = curatorFramework.getData().forPath(datasourceParh);
            String datasourceJson = new String(datasourceData);
            logger.debug("获取到zookeeper的数据:{}",datasourceJson);
            Gson gson = new GsonBuilder().serializeNulls().create();
            ZookeeperDataSource zookeeperDataSource = gson.fromJson(datasourceJson,ZookeeperDataSource.class);
            if(zookeeperDataSource == null) {
                return druidDataSource;
            }
            druidDataSource.setUrl(zookeeperDataSource.getUrl());
            druidDataSource.setUsername(zookeeperDataSource.getUsername());
            druidDataSource.setPassword(zookeeperDataSource.getPassword());
            druidDataSource.setDriverClassName(zookeeperDataSource.getDriver());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return druidDataSource;
    }
}

Zookeeper上配置的数据源信息,直接存储了json数据

此时启动项目,在PostMan中调用接口测试

虽然SpringBoot的配置文件中没有配置数据源基本信息,但程序依旧运行正常

3.3.5.动态修改数据源

添加Zookeeper监听器,当数据节点的值发生变化时重新启动DataSource并设置修改后的值

@Component
public class ZookeeperListener {
    private static Logger logger = LogManager.getLogger(ZookeeperListener.class);

    @Value("${zookeeper.listenerPath}")
    private String listenerPath;

    @Resource
    private CuratorFramework client;

    @Resource
    private DruidDataSource dataSource;

    @PostConstruct
    public void start() throws Exception {
        //创建监听
        PathChildrenCache cache = new PathChildrenCache(client, "/zookeeper",true);
        cache.start();
        cache.rebuild();
        cache.getListenable().addListener((CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) -> {
            PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
            ChildData data = pathChildrenCacheEvent.getData();
            List<ChildData> initialData = pathChildrenCacheEvent.getInitialData();
            logger.debug("节点发生变化,type = {} data = {} initialData = {}",type,data,initialData);

            if(data != null && listenerPath.equals(data.getPath())) {
                    byte[] datasourceData = data.getData();
                    String datasourceJson = new String(datasourceData);
                    logger.debug("获取到zookeeper的数据:{}",datasourceJson);
                    Gson gson = new GsonBuilder().serializeNulls().create();
                    ZookeeperDataSource zookeeperDataSource = gson.fromJson(datasourceJson,ZookeeperDataSource.class);
                    if(zookeeperDataSource != null) {
                        dataSource.restart();
                        dataSource.setUrl(zookeeperDataSource.getUrl());
                        dataSource.setUsername(zookeeperDataSource.getUsername());
                        dataSource.setPassword(zookeeperDataSource.getPassword());
                        dataSource.setDriverClassName(zookeeperDataSource.getDriver());
                    }
            }
        });
    }
}

这里为了测试,新建了一个数据库,测试动态数据库的变更

重新启动程序,调用接口,程序运行正常(注意此时返回的id为1)

然后通过Zookeeper客户端修改datasource的值(此处仅修改了database)

set /zookeeper/datasource {"username":"xxx","password":"xxx","url":"jdbc:mysql://192.168.1.208:9906/poiuy_study_bak?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai","driver":"com.mysql.cj.jdbc.Driver"}

在程序后台console中可以看到Zookeeper监听到数据变化后重新获取数据源配置并重启DruidDataSource

此时再次调用接口可以看到获取的值是更换后的数据库的数据

相关推荐

好用的云函数!后端低代码接口开发,零基础编写API接口

前言在开发项目过程中,经常需要用到API接口,实现对数据库的CURD等操作。不管你是专业的PHP开发工程师,还是客户端开发工程师,或者是不懂编程但懂得数据库SQL查询,又或者是完全不太懂技术的人,通过...

快速上手:Windows 平台上 cURL 命令的使用方法

在工作流程中,为了快速验证API接口有效性,团队成员经常转向直接执行cURL命令的方法。这种做法不仅节省时间,而且促进了团队效率的提升。对于使用Windows系统的用户来说,这里有一套详细...

使用 Golang net/http 包:基础入门与实战

简介Go的net/http包是构建HTTP服务的核心库,功能强大且易于使用。它提供了基本的HTTP客户端和服务端支持,可以快速构建RESTAPI、Web应用等服务。本文将介绍ne...

#小白接口# 使用云函数,人人都能编写和发布自己的API接口

你只需编写简单的云函数,就可以实现自己的业务逻辑,发布后就可以生成自己的接口给客户端调用。果创云支持对云函数进行在线接口编程,进入开放平台我的接口-在线接口编程,设计一个新接口,设计和配置好接口参...

极度精神分裂:我家没有墙面开关,但我虚拟出来了一系列开关

本内容来源于@什么值得买APP,观点仅代表作者本人|作者:iN在之前和大家说过,在iN的家里是没有墙面开关的。...

window使用curl命令的注意事项 curl命令用法

cmd-使用curl命令的注意点前言最近在cmd中使用curl命令来测试restapi,发现有不少问题,这里记录一下。在cmd中使用curl命令的注意事项json不能由单引号包括起来json...

Linux 系统curl命令使用详解 linuxctrl

curl是一个强大的命令行工具,用于在Linux系统中进行数据传输。它支持多种协议,包括HTTP、HTTPS、FTP等,用于下载或上传数据,执行Web请求等。curl命令的常见用法和解...

Tornado 入门:初学者指南 tornados

Tornado是一个功能强大的PythonWeb框架和异步网络库。它最初是为了处理实时Web服务中的数千个同时连接而开发的。它独特的Web服务器和框架功能组合使其成为开发高性能Web...

PHP Curl的简单使用 php curl formdata

本文写给刚入PHP坑不久的新手们,作为工具文档,方便用时查阅。CURL是一个非常强大的开源库,它支持很多种协议,例如,HTTP、HTTPS、FTP、TELENT等。日常开发中,我们经常会需要用到cur...

Rust 服务器、服务和应用程序:7 Rust 中的服务器端 Web 应用简介

本章涵盖使用Actix提供静态网页...

我给 Apache 顶级项目提了个 Bug apache顶级项目有哪些

这篇文章记录了给Apache顶级项目-分库分表中间件ShardingSphere提交Bug的历程。说实话,这是一次比较曲折的Bug跟踪之旅。10月28日,我们在GitHub上提...

linux文件下载、服务器交互(curl)

基础环境curl命令描述...

curl简单使用 curl sh

1.curl--help#查看关键字2.curl-A“(添加user-agent<name>SendUser-Agent<name>toserver)”...

常用linux命令:curl 常用linux命令大全

//获取网页内容//不加任何选项使用curl时,默认会发送GET请求来获取内容到标准输出$curlhttp://www.baidu.com//输出<!DOCTYPEh...

三十七,Web渗透提高班之hack the box在线靶场注册及入门知识

一.注册hacktheboxHackTheBox是一个在线平台,允许测试您的渗透技能和代码,并与其他类似兴趣的成员交流想法和方法。它包含一些不断更新的挑战,并且模拟真实场景,其风格更倾向于CT...