springboot+dynamicDataSource动态添加切换数据源方式

使用 Spring Boot,可以动态添加切换数据源,需要用到Spring JDBC模块中的 AbstractRoutingDataSource 类和 DynamicDataSourceHolder 维护一个存储当前使用的数据源 key 的 ThreadLocal 对象。步骤如下:

导入依赖

首先,在 pom.xml 中导入 Spring Boot 和 Spring JDBC 的依赖。

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

定义数据源

其次,在 application.yml 中定义数据源。

spring:
  datasource:
    default:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
      username: root
      password: root
    db1:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=UTF-8
      username: root
      password: root
    db2:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=UTF-8
      username: root
      password: root

定义动态数据源

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceHolder.getDataSourceKey();
    }
}

维护当前使用数据源的 key

public class DynamicDataSourceHolder {
    private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<>();

    public static void setDataSourceKey(String key) {
        dataSourceKey.set(key);
    }

    public static String getDataSourceKey() {
        return dataSourceKey.get();
    }

    public static void clearDataSourceKey() {
        dataSourceKey.remove();
    }
}

配置动态数据源

@Configuration
public class DataSourceConfig {
    @Bean
    @ConfigurationProperties("spring.datasource")
    public DataSource defaultDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.db1")
    public DataSource db1DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.db2")
    public DataSource db2DataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public DynamicDataSource dynamicDataSource() {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("default", defaultDataSource());
        targetDataSources.put("db1", db1DataSource());
        targetDataSources.put("db2", db2DataSource());

        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource());

        return dynamicDataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(dynamicDataSource);

        return sqlSessionFactory;
    }
}

上述代码中,@ConfigurationProperties("spring.datasource") 表示读取 yml 配置文件中的 spring.datasource 参数,这里将 default 数据源的信息读入 DataSource 中,其他两个数据源同理。DynamicDataSource 类是继承了 Spring JDBC 中的 AbstractRoutingDataSource 类,它会调用 DynamicDataSourceHolder 中的 getDataSourceKey() 方法获取当前数据源 key,然后根据这个 key 从 targetDataSources 中取出对应的数据源。

测试

为了方便测试,我们添加 Controller 和 Service。

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public User findById(@PathVariable Integer id, @RequestParam String db) {
        DynamicDataSourceHolder.setDataSourceKey(db);
        User user = userService.findById(id);
        DynamicDataSourceHolder.clearDataSourceKey();

        return user;
    }
}

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User findById(Integer id) {
        return userMapper.findById(id);
    }
}

@Mapper
public interface UserMapper {
    User findById(Integer id);
}

这个示例中,我们为 Controller 增加了一个请求参数 db,它的值可以是 default、db1 或 db2,为了测试是否切换了数据源,我们在 findById() 方法中调用 DynamicDataSourceHolder.setDataSourceKey() 方法设置数据源 key,然后在调用 UserService.findById() 方法完成查询后,调用 DynamicDataSourceHolder.clearDataSourceKey() 方法清除数据源 key,这样就完成了数据源的切换。

$ curl http://localhost:8080/user/1?db=db1
{"id":1,"name":"User 1","age":20}
$ curl http://localhost:8080/user/2?db=db2
{"id":2,"name":"User 2","age":30}

根据访问地址中的 db 参数的值,会分别从 db1 和 db2 数据库中查询数据。

可以看到,使用 Spring Boot 实现动态添加切换数据源非常简单。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:springboot+dynamicDataSource动态添加切换数据源方式 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Java线程安全的计数器简单实现代码示例

    下面就是“Java线程安全的计数器简单实现代码示例”的完整攻略。 什么是线程安全? 在讲解线程安全的计数器实现前,必须先了解什么是线程安全。简而言之,线程安全是指程序的多线程执行不会影响程序整体执行结果的正确性。 在Java中,线程安全通常是指多线程执行同样的代码时,不会出现数据竞争、死锁等问题。 如何实现线程安全的计数器? 实现线程安全的计数器,可以采用多…

    Java 2023年5月19日
    00
  • JAVA对象和字节数组互转操作

    Java对象和字节数组互转操作是Java编程中常见的技巧之一。在某些情况下,我们需要把Java对象序列化成字节数组,再把字节数组反序列化为Java对象,这样可以在网络传输、文件存储等场景中实现数据的传输和存储。本文以Java 8为例,讲解Java对象和字节数组互转的完整攻略。 1. Java对象转字节数组 Java对象转字节数组需要使用到Java的序列化机制…

    Java 2023年5月26日
    00
  • Java基于Dijkstra算法实现校园导游程序

    Java基于Dijkstra算法实现校园导游程序攻略 1. 确定算法 首先,我们需要确定使用什么算法来实现校园导游程序,此处我们选择使用Dijkstra算法。 Dijkstra算法是一种用于带权图的单源最短路径算法,可以帮助我们找到两点之间的最短路径。在本程序中,我们需要将所有景点看作节点,将各个景点之间的距离看作边权,应用Dijkstra算法求解距离最短的…

    Java 2023年5月19日
    00
  • java使用IO流对数组排序实例讲解

    Java使用IO流对数组排序实例讲解 简介 本文介绍了使用Java的IO流对数组进行排序的方法,以及解释了IO流和排序的概念,也包含了两个示例。 IO流和排序简介 IO流 IO流是Java中对输入输出流的统称,分为字节流和字符流,其中字节流主要处理二进制文件,而字符流则主要用于文本文件。在Java中,使用IO流需要借助InputStream、OutputSt…

    Java 2023年5月26日
    00
  • javascript基于原型链的继承及call和apply函数用法分析

    JavaScript基于原型链的继承 什么是继承 在面向对象编程中,继承是一种允许新对象获取现有对象的属性和方法的机制。它允许我们创建继承现有对象的新对象,从而减少代码重复,增加代码可重用性。 JavaScript中基于原型链的继承 在JavaScript中,没有像其他语言一样的类和接口的概念,继承通过原型链来实现。每个对象都有一个原型对象,原型对象又有自己…

    Java 2023年5月26日
    00
  • Java如何使用spire进行word文档的替换详解

    什么是Spire.Doc?Spire.Doc是一个专业的Word .NET库,支持生成、操作、查看、读取和转换Word文档,包括doc、docx、rtf、txt等文档格式。Spire.Doc能够让开发者快速地添加内容和格式化文档,并将文档导出为一种格式。 如何使用Spire进行word文档替换的详细攻略 首先,我们需要引用Spire.Doc的命名空间,并且创…

    Java 2023年5月26日
    00
  • Spring Security密码解析器PasswordEncoder自定义登录逻辑

    概述: Spring Security 的 PasswordEncoder 用于对用户的密码进行加密(哈希处理)和解密,提供了很多加密算法,但是在某些情况下,我们需要自定义一些特殊的登录逻辑。本文将详细介绍如何自定义登录逻辑,实现 PasswordEncoder 的自定义。 过程: 1.继承PasswordEncoder接口,实现自定义逻辑的加密方法。 pu…

    Java 2023年6月3日
    00
  • java 解决Eclipse挂掉问题的方法

    Java 解决 Eclipse 挂掉问题的方法 在开发 Java 项目过程中,有时会遇到 Eclipse 挂掉的情况。这可能是由于运行环境问题、占用内存过多造成的。下面介绍几种常用方法来解决 Eclipse 挂掉问题。 方法一:修改 Eclipse.ini 文件 在 Eclipse 的安装目录下找到 Eclipse.ini 文件(Windows 系统默认安装…

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部