Springboot动态切换数据源的具体实现与原理分析

下面开始讲解“Springboot动态切换数据源的具体实现与原理分析”的完整攻略。

一. 实现原理分析

1.1. 多数据源的实现方式

在多数据源的实现中,我们不能像单数据源的实现那样,在 application.properties 或 application.yml 中写入数据源的配置信息。我们需要寻找一种实现方式,能够在程序运行期间动态配置数据源信息。

1.2. 动态数据源的实现方式

Springboot 动态切换数据源的实现方式主要依靠AbstractRoutingDataSource。

AbstractRoutingDataSource 是 Spring 中的一个抽象类,可以做到根据某种标识进行切换数据源操作。通过继承 AbstractRoutingDataSource,并重写其中的 determineCurrentLookupKey() 方法,我们可以实现多数据源之间的切换。

1.3. 实现步骤

  1. 在 pom.xml 中添加相关依赖

多数据源的实现首先需要引入多个数据源实现的依赖包。例如,在下面的示例中我们使用了 druid 和 mysql-connector-java 作为我们的两个数据源。

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.16</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
  1. 定义数据源枚举类

在多数据源实现的过程中,我们需要通过枚举类的方式来定义多个数据源信息。枚举类中需要包含数据源的相关信息,例如数据库连接信息、数据库用户名、数据库密码等。

public enum DataSourceEnum {
    DS_KEY_MASTER("master", "jdbc:mysql://localhost:3306/test1?characterEncoding=UTF-8&useSSL=false", "root", "root"),
    DS_KEY_SLAVE("slave", "jdbc:mysql://localhost:3306/test2?characterEncoding=UTF-8&useSSL=false", "root", "root");

    private String key;

    private String url;

    private String userName;

    private String password;

    DataSourceEnum(String key, String url, String userName, String password) {
        this.key = key;
        this.url = url;
        this.userName = userName;
        this.password = password;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
  1. 编写 AbstractRoutingDataSource 的子类

在编写 AbstractRoutingDataSource 的子类时,我们需要重写其中的 determineCurrentLookupKey() 这个方法。在这个方法中,我们需要根据具体的场景来确定哪个数据源将被返回。

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceHolder.getDataSourceKey();
    }
}
  1. 编写自定义数据源切换工具类

自定义数据源切换工具类用于在程序运行时实现数据源切换。在这个类中,我们主要是编写了一个切换数据源的方法 switchDataSource(),这个方法会将指定的数据源切换为当前的数据源。

public class DataSourceSwitcher {

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

    public static void setDataSource(String dataSourceKey) {
        dataSources.set(dataSourceKey);
    }

    public static String getDataSource() {
        return dataSources.get();
    }

    public static void clearDataSource() {
        dataSources.remove();
    }

}
  1. 编写数据源切换 AOP 拦截器

在进行数据源切换时,我们需要编写一个 AOP 拦截器来切换数据源。在这个拦截器中,我们需要实现在访问数据库之前切换数据源。

@Aspect
@Component
public class DataSourceInterceptor {

    @Pointcut("execution(* com.cxy.demo.springbootdemo.controller..*.*(..))")
    public void dataSourcePointCut() {
    }

    @Before("dataSourcePointCut()")
    public void dataSourceBeforeHandle(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Class<?> targetClass = joinPoint.getTarget().getClass();
        Method method = signature.getMethod();
        DataSource dataSourceAnno = method.getAnnotation(DataSource.class);
        if (dataSourceAnno == null) {
            dataSourceAnno = AnnotationUtils.findAnnotation(targetClass, DataSource.class);
        }
        if (dataSourceAnno != null) {
            String dsId = dataSourceAnno.value();
            DataSourceSwitcher.setDataSource(dsId);
        }
    }

    @After("dataSourcePointCut()")
    public void after() {
        DataSourceSwitcher.clearDataSource();
    }

}

二. 实现示例

下面是两个简单的示例代码,主要是演示了在程序运行时如何切换数据源。

2.1. 示例 1:在 Service 层中进行数据源的切换

在这个示例中,我们实现了两个简单的查询操作,并且这两个操作所使用的数据源是不同的。具体的实现过程如下:

  1. 首先在 application.properties 中配置数据源相关信息,例如:
spring.datasource.master.url=jdbc:mysql://localhost:3306/test1?characterEncoding=UTF-8&useSSL=false
spring.datasource.master.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.master.username=root
spring.datasource.master.password=root
spring.datasource.master.type=com.alibaba.druid.pool.DruidDataSource

spring.datasource.slave.url=jdbc:mysql://localhost:3306/test2?characterEncoding=UTF-8&useSSL=false
spring.datasource.slave.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.slave.username=root
spring.datasource.slave.password=root
spring.datasource.slave.type=com.alibaba.druid.pool.DruidDataSource
  1. 在 Service 层中调用两个方法,获取两个不同的数据源。
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    @DataSource("master")
    public List<User> getUserListFromMaster() {
        return userMapper.getUserList();
    }

    @Override
    @DataSource("slave")
    public List<User> getUserListFromSlave() {
        return userMapper.getUserList();
    }

}

注意:在这里我们使用了注解 @DataSource 来指定具体的数据源。

  1. 最后,在 Mapper 层中使用 XML 的方式来实现具体的 SQL 操作。

2.2. 示例 2:在 Controller 层中进行数据源的切换

在这个示例中,我们实现一个简单的查询操作,并且我们将数据源的切换放在 Controller 层中进行。具体的实现过程如下:

  1. 在我们的 application.properties 中配置数据源信息。

  2. 在 Controller 层中实现具体的查询操作。在这个操作中,我们需要指定相关的数据源信息。

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/list")
    public List<User> getUserList() {
        DataSourceSwitcher.setDataSource("master");
        List<User> userList = userService.getUserListFromMaster();
        DataSourceSwitcher.clearDataSource();
        return userList;
    }

}

注意:在这里我们使用了类 DataSourceSwitcher来动态控制数据源的切换。在程序运行的过程中,我们可以在需要切换数据源的地方调用 DataSourceSwitcher.setDataSource() 方法来实现数据源的切换。

三. 参考链接

  • SpringBoot实现动态切换数据源(一):https://www.jianshu.com/p/3a3aaff7e6b8
  • SpringBoot实现动态切换数据源(二):https://www.jianshu.com/p/ea413ce69d65
  • Springboot使用druid实现多数据源配置与动态切换:https://www.jianshu.com/p/1878f12ce88f

以上是“Springboot动态切换数据源的具体实现与原理分析”的完整攻略,如果您还有任何问题,欢迎发出跟进提问。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Springboot动态切换数据源的具体实现与原理分析 - Python技术站

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

相关文章

  • tomcat常见的错误与解决方案小结

    Tomcat常见的错误与解决方案小结 1. 端口被占用 当我们启动Tomcat时,有时候会遇到端口被占用的情况,这时候Tomcat就会启动失败。我们可以通过以下几个步骤来解决这个问题: 方案一:杀掉占用端口的进程 打开命令行 输入 netstat -ano 查看占用端口的进程ID 输入 taskkill /pid 进程ID /f 杀掉该进程 重新启动Tomc…

    Java 2023年5月19日
    00
  • Java中如何将json字符串转换成map/list

    将JSON字符串转换为Map/List是Java编程中非常常见的操作,可以使用第三方库如Jackson、Gson和Fastjson等来实现。以下是使用Jackson和Fastjson两种库实现的示例说明: 使用Jackson库实现 首先,需要在pom.xml中添加Jackson库的依赖: xml <dependency> <groupId&…

    Java 2023年5月26日
    00
  • Java 如何解析key为动态的json操作

    使用JsonNode解析动态key的Json 使用Jackson库中的JsonNode对象可以在解析动态key的Json时非常有用。JsonNode对象可以类比Java的DOM节点进行操作从而解析Json。可以像以下这样使用JsonNode解析动态key的Json: String jsonString = "{\"key1\":…

    Java 2023年5月26日
    00
  • 新的Java访问mysql数据库工具类的操作代码

    下面我将详细讲解“新的Java访问MySQL数据库工具类的操作代码”的完整攻略。 简述 在Java程序中访问MySQL数据库通常需要使用JDBC驱动,JDBC驱动是一组API,用于与不同的关系型数据库进行通信。使用JDBC驱动连接MySQL数据库可以使用原生JDBC API,也可以使用更方便的第三方库,如JdbcTemplate和MyBatis等。 我们可以…

    Java 2023年5月19日
    00
  • Spring Boot超详细分析启动流程

    Spring Boot是基于Spring框架的一种快速开发框架,它通过自动化配置和约定大于配置的方式,可以快速的搭建一个Web应用。 Spring Boot启动流程主要分为三个阶段:准备阶段、上下文创建阶段、启动阶段。 准备阶段 Spring Boot准备阶段主要是读取应用程序的配置文件,获取配置文件中自定义的配置内容,并为后续的启动做好一些准备工作。准备阶…

    Java 2023年5月19日
    00
  • 当 SQL Server(mssql-jdbc) 遇上 BigDecimal → 精度丢失,真坑!

    开心一刻   中午和哥们一起喝茶   哥们说道:晚上喝酒去啊   我:不去,我女朋友过生日   哥们瞪大眼睛看着我:你有病吧,充气的过什么生日   我生气到:有特么生产日期的好吧 需求背景   系统对接了外部系统,调用外部系统的接口需要付费,一个接口一次调用付费 0.03 元   同一个月内,同一个接口最高付费 25 元   统计每个月的付费情况   需求清…

    Java 2023年4月28日
    00
  • Java集合Iterator迭代的实现方法

    下面是关于Java集合Iterator迭代的实现方法的完整攻略: 什么是Java迭代器 Java迭代器是一种设计模式,可以通过这种模式在不暴露集合内部结构的情况下遍历集合中的元素。 Java集合框架中的所有类都实现了java.util.Iterator 接口,这个接口内部定义了三个方法: hasNext():判断当前位置后是否还有元素 next():获取下一…

    Java 2023年5月26日
    00
  • 解决@PathVariable出现点号.时导致路径参数截断获取不全的问题

    在Spring MVC中,@PathVariable注解用于从URL中提取路径参数。但是,当路径参数中包含点号(.)时,Spring MVC会将其解释为文件扩展名,导致路径参数截断获取不全的问题。在本文中,我们将详细讲解如何解决这个问题,并提供两个示例来说明这个过程。 解决方案 要解决@PathVariable出现点号.时导致路径参数截断获取不全的问题,我们…

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