Spring(AbstractRoutingDataSource)实现动态数据源切换示例

下面为你详细讲解Spring中如何使用抽象路由数据源(AbstractRoutingDataSource)实现动态数据源切换,包含两个示例。

1. 动态数据源切换

动态数据源切换指的是可以动态地选择使用哪个数据源来进行数据访问,一般用于多数据源的情况下。使用抽象路由数据源(AbstractRoutingDataSource)可以方便地实现数据源动态切换。

2. 抽象路由数据源(AbstractRoutingDataSource)

抽象路由数据源(AbstractRoutingDataSource)是Spring提供的一个抽象类,它继承了Spring的SimpleDriverDataSource,并实现了Spring的DataSource接口,在实现过程中通过维护一个ThreadLocal变量来存储当前使用的数据源。

使用抽象路由数据源(AbstractRoutingDataSource)来实现动态数据源切换,需要继承该类并重写其中的determineCurrentLookupKey方法,该方法返回一个字符串,用来表示当前要使用哪个数据源。

3. 示例一

下面是一个示例,演示如何实现基于注解的动态数据源切换。

3.1 首先创建两个数据源

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

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

3.2 创建动态数据源

@Configuration
public class DynamicDataSourceConfig {
    @Bean
    public AbstractRoutingDataSource routingDataSource(DataSource masterDataSource, DataSource slaveDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDataSource);
        targetDataSources.put("slave", slaveDataSource);
        AbstractRoutingDataSource routingDataSource = new AbstractRoutingDataSource() {
            @Override
            protected Object determineCurrentLookupKey() {
                return DataSourceContextHolder.getDataSourceType();
            }
        };
        routingDataSource.setTargetDataSources(targetDataSources);
        routingDataSource.setDefaultTargetDataSource(masterDataSource);
        return routingDataSource;
    }
}

3.3 创建数据源上下文

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSourceType(String type) {
        contextHolder.set(type);
    }

    public static String getDataSourceType() {
        return contextHolder.get();
    }

    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

3.4 创建注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataSource {
    String value() default "master";
}

3.5 创建切面

@Aspect
@Component
public class DataSourceAspect {
    @Before("@annotation(dataSource)")
    public void changeDataSource(JoinPoint point, DataSource dataSource) {
        DataSourceContextHolder.setDataSourceType(dataSource.value());
    }

    @After("@annotation(dataSource)")
    public void restoreDataSource(JoinPoint point, DataSource dataSource) {
        DataSourceContextHolder.clearDataSourceType();
    }
}

3.6 使用示例

@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    @Transactional
    @DataSource("master")
    public void save(User user) {
        userDao.save(user);
    }

    @Transactional(readOnly = true)
    @DataSource("slave")
    public List<User> findAll() {
        return userDao.findAll();
    }
}

4. 示例二

下面是另一个示例,演示如何通过配置文件来实现基于注解的动态数据源切换。

4.1 创建动态数据源

public class RoutingDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceType();
    }
}

4.2 创建数据源上下文

public class DataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSourceType(String type) {
        contextHolder.set(type);
    }

    public static String getDataSourceType() {
        return contextHolder.get();
    }

    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

4.3 配置文件

spring:
  datasource:
    type: class
    driver-class-name: com.mysql.jdbc.Driver
    master:
        url: jdbc:mysql://localhost:3306/db_master?useSSL=false
        username: root
        password: root
    slave:
        url: jdbc:mysql://localhost:3306/db_slave?useSSL=false
        username: root
        password: root

datasource:
    type: routing
    datasource:
        master:
            - jdbc:mysql://localhost:3306/db_master?useSSL=false
            - root
            - root
        slave:
            - jdbc:mysql://localhost:3306/db_slave?useSSL=false
            - root
            - root

4.4 读取配置

@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceConfig {
    @Bean
    @Primary
    public DataSource masterDataSource(DataSourceProperties properties) {
        String url = properties.getDatasource().get("master").get(0);
        String username = properties.getDatasource().get("master").get(1);
        String password = properties.getDatasource().get("master").get(2);
        return DataSourceBuilder.create().url(url).username(username).password(password).build();
    }

    @Bean
    public DataSource slaveDataSource(DataSourceProperties properties) {
        String url = properties.getDatasource().get("slave").get(0);
        String username = properties.getDatasource().get("slave").get(1);
        String password = properties.getDatasource().get("slave").get(2);
        return DataSourceBuilder.create().url(url).username(username).password(password).build();
    }

    @Bean
    public RoutingDataSource routingDataSource(DataSource masterDataSource, DataSource slaveDataSource) {
        RoutingDataSource routingDataSource = new RoutingDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDataSource);
        targetDataSources.put("slave", slaveDataSource);
        routingDataSource.setTargetDataSources(targetDataSources);
        routingDataSource.setDefaultTargetDataSource(masterDataSource);
        return routingDataSource;
    }
}

4.5 创建注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataSource {
    String value() default "master";
}

4.6 创建切面

@Aspect
@Component
public class DataSourceAspect {
    @Before("@annotation(dataSource)")
    public void changeDataSource(JoinPoint point, DataSource dataSource) {
        DataSourceContextHolder.setDataSourceType(dataSource.value());
    }

    @After("@annotation(dataSource)")
    public void restoreDataSource(JoinPoint point, DataSource dataSource) {
        DataSourceContextHolder.clearDataSourceType();
    }
}

4.7 使用示例

@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    @Transactional
    @DataSource("master")
    public void save(User user) {
        userDao.save(user);
    }

    @Transactional(readOnly = true)
    @DataSource("slave")
    public List<User> findAll() {
        return userDao.findAll();
    }
}

以上就是使用抽象路由数据源(AbstractRoutingDataSource)实现动态数据源切换的两个示例,具体使用方法可参考代码。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring(AbstractRoutingDataSource)实现动态数据源切换示例 - Python技术站

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

相关文章

  • Tomcat源码解析之Web请求与处理

    Tomcat源码解析之Web请求与处理 前言 Tomcat 是一个流行的Web应用服务器,也是一个开源项目。对于二次开发者,学习Tomcat的源码是非常有益的。本文将对Tomcat的Web请求与处理进行深入的源码解析。 一、Tomcat的主要入口 Tomcat的Http处理入口是由org.apache.catalina.core.StandardHostVa…

    Java 2023年5月20日
    00
  • 什么是 JIT 编译器?

    以下是关于JIT编译器的完整使用攻略: 什么是JIT编译器? JIT(Just-In-Time)编译器是一种在程序运行时将字节码编译成本地机器码的编译器。JIT编译器可以提高程序的执行速度,因为它可以将热点代码(即经常执行的代码)编译成本地机器码,从而避免了每次执行时都需要解释字节码的开销。 JIT编译器的优点 JIT编译器有以下优点: 提高程序的执行速度:…

    Java 2023年5月12日
    00
  • java.lang.UnsatisfiedLinkError: %1 不是有效的Win32应用程序错误解决

    当在Windows平台上运行Java程序时,可能会遇到java.lang.UnsatisfiedLinkError: %1 不是有效的Win32应用程序错误。这个错误通常表示尝试加载一个非Win32本机库的错误,或者尝试加载一个Win32本地库,但在可执行文件中找不到该库的指定扩展名。 要解决此错误,可以尝试以下方法: 1. 检查本机库是否具有正确的位数 如…

    Java 2023年5月25日
    00
  • 浅谈Java几种文件读取方式耗时

    标题:浅谈Java几种文件读取方式耗时 正文:文件读取是Java程序中常见的操作,经常会涉及到从磁盘读取文件。文件读取操作的耗时对程序的影响非常大,因此有必要深入了解Java中几种文件读取方式的优劣性。 传统IO流的文件读取方式 传统的IO流文件读取方式使用FileInputStream和BufferedInputStream来读取文件,主要原理是将文件内容…

    Java 2023年5月20日
    00
  • IDEA项目使用SpringBoot+MyBatis-Plus的方法

    这里是详细的讲解“IDEA项目使用SpringBoot+MyBatis-Plus的方法”的完整攻略,包含了两条示例。 准备条件 为了完成本攻略,你需要事先准备以下条件: JDK 8及以上版本 IntelliJ IDEA 2020.3或以上版本 Maven 3.0及以上版本 SpringBoot 2.4.x版本 MyBatis-Plus 3.x版本 数据库(本…

    Java 2023年5月20日
    00
  • SpringBoot浅析安全管理之高级配置

    Spring Boot浅析安全管理之高级配置 Spring Boot提供了强大的安全管理功能,可以帮助开发人员保护应用程序的安全性。在本文中,我们将深入探讨Spring Boot安全管理的高级配置。 Spring Boot安全管理的基本概念 在Spring Boot中,安全管理是指保护应用程序的机制,以确保只有授权用户才能访问应用程序的资源。Spring B…

    Java 2023年5月15日
    00
  • Java 文件上传的实例详解

    下面就详细讲解一下“Java 文件上传的实例详解”的完整攻略。 简介 Java 文件上传是一项常见的网络应用需求,例如图片上传、文件上传等场景。通过使用 Java 语言和相关的框架,我们可以轻松实现一个强大、安全和高效的文件上传应用。 通用的文件上传实现步骤 对于大部分文件上传场景,我们可以采取以下步骤来实现: 在客户端,通过 HTML 表单或 JavaSc…

    Java 2023年5月20日
    00
  • Java SpringBoot整合shiro-spring-boot-starterqi项目报错解决

    针对“Java SpringBoot整合shiro-spring-boot-starterqi项目报错解决”的问题,我们可以按照以下步骤进行解决: 1. 引入shiro-spring-boot-starter 在pom.xml中加入以下依赖配置 <dependency> <groupId>org.apache.shiro</gr…

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