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

下面就来详细讲解“SpringBoot基于AbstractRoutingDataSource实现多数据源动态切换”的完整攻略:

什么是AbstractRoutingDataSource

Spring中提供了AbstractRoutingDataSource抽象类,该抽象类继承自AbstractDataSource类,用于实现多数据源的动态切换。继承该抽象类并实现其中的determineCurrentLookupKey()方法,可以根据每次访问时的参数确定该使用哪个数据源,从而实现动态切换多个数据源。

实现多数据源动态切换的步骤

  1. 首先,需要定义每个数据源的相关配置信息,例如数据库URL、用户名、密码等信息。可以通过在application.properties文件中定义多组数据源的方式来实现:
# 主数据源
spring.datasource.url=jdbc:mysql://localhost:3306/test1
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

# 数据源1
datasource1.url=jdbc:mysql://localhost:3306/test2
datasource1.username=root
datasource1.password=123456
datasource1.driver-class-name=com.mysql.jdbc.Driver

# 数据源2
datasource2.url=jdbc:mysql://localhost:3306/test3
datasource2.username=root
datasource2.password=123456
datasource2.driver-class-name=com.mysql.jdbc.Driver
  1. 接着,在自定义的数据源配置类中添加@Configuration@Primary注解,以及定义主数据源,并且需要将其他的数据源也注入进来,并对每个数据源分别起一个标识符:
@Configuration
public class DataSourceConfig {

    @Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "dataSource1")
    @ConfigurationProperties(prefix = "datasource1")
    public DataSource dataSource1() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "dataSource2")
    @ConfigurationProperties(prefix = "datasource2")
    public DataSource dataSource2() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 使用DynamicDataSource,避免直接注入dataSource实现动态数据源切换
     *
     * @return
     */
    @Bean(name = "dynamicDataSource")
    public DynamicDataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> dataSourceMap = new HashMap<>();
        dataSourceMap.put("primaryDataSource", primaryDataSource());
        dataSourceMap.put("dataSource1", dataSource1());
        dataSourceMap.put("dataSource2", dataSource2());
        dynamicDataSource.setDefaultTargetDataSource(primaryDataSource());
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        return dynamicDataSource;
    }
}
  1. 实现动态切换,创建自定义的数据源类DynamicDataSource,该类继承自AbstractRoutingDataSource,并重写其中的determineCurrentLookupKey()方法,根据不同的参数,动态地切换使用的数据源:
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceKey();
    }

}
  1. 为了实现更方便的动态切换数据源,需要创建一个线程本地变量DataSourceContextHolder,用来保存当前使用的数据源标识符。可以使用ThreadLocal保证每个线程独立使用自己的数据源:
public class DataSourceContextHolder {

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

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

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

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

}
  1. 最后,在需要访问不同数据源的Service方法上使用@DataSource注解,通过注解的参数来指定当前需要使用的数据源标识符,然后将该注解添加到一个切面中:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {

    /**
     * 切换到的数据源名称
     */
    String value();

}
@Aspect
@Component
public class DataSourceAspect {

    @Pointcut("@annotation(com.example.demo.datasource.annotation.DataSource)")
    public void dataSourcePointCut() {
    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        DataSource dataSource = method.getAnnotation(DataSource.class);
        if (dataSource != null) {
            String dataSourceKey = dataSource.value();
            DataSourceContextHolder.setDataSourceKey(dataSourceKey);
        }
        try {
            return point.proceed();
        } finally {
            DataSourceContextHolder.clearDataSourceKey();
        }
    }
}

示例

下面列举两个简单示例:

  1. 每个数据源的连接配置是由用户输入的:
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    @DataSource("primaryDataSource")
    public List<User> getAllUsers() {
        return userDao.getAllUsers();
    }

    @Override
    public List<User> getAllUsersByDataSource(String url, String userName, String password) {
        DynamicDataSource dynamicDataSource = (DynamicDataSource) DataSourceContextHolder.getApplicationContext()
                .getBean("dynamicDataSource");
        DataSource dataSource = DataSourceBuilder.create()
                .driverClassName("com.mysql.cj.jdbc.Driver")
                .url(url)
                .username(userName)
                .password(password)
                .build();
        dynamicDataSource.addTargetDataSource("externalDataSource", dataSource);
        DataSourceContextHolder.setDataSourceKey("externalDataSource");
        List<User> userList = userDao.getAllUsers();
        DataSourceContextHolder.clearDataSourceKey();
        dynamicDataSource.removeTargetDataSource("externalDataSource");
        return userList;
    }
}

在该示例中,每次访问的数据源需要从方法参数中获取,于是我们可以创建一个新数据源,在使用完毕之后再将其销毁。方法上使用了@DataSource注解,指定了默认数据源。

  1. 每个数据源的连接配置固定,并定义了两个不同的数据源:
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    @DataSource("primaryDataSource")
    public List<User> getAllUsers() {
        return userDao.getAllUsers();
    }

    @Override
    @DataSource("dataSource1")
    public List<User> getAllUsersByDataSourceA() {
        return userDao.getAllUsers();
    }

    @Override
    @DataSource("dataSource2")
    public List<User> getAllUsersByDataSourceB() {
        return userDao.getAllUsers();
    }
}

在该示例中,每个@DataSource注解都在对应的Service方法上进行了指定。

通过以上步骤和示例,就可以实现多数据源动态切换了。

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

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

相关文章

  • 详解Spring Boot 部署jar和war的区别

    接下来我将详细讲解“详解Spring Boot 部署jar和war的区别”的完整攻略。 1. 什么是Spring Boot? Spring Boot是一个基于Spring框架的开发和部署工具,它可以帮助开发者快速搭建和部署Spring应用。Spring Boot提供了许多便捷的功能,可以使Java应用开发更加高效和简便。 2. Spring Boot部署方式…

    Java 2023年5月20日
    00
  • SpringBoot整合Spring Data JPA的详细方法

    Spring Boot整合Spring Data JPA的详细方法 Spring Data JPA是Spring Framework的一部分,它提供了一种方便的方式来访问和操作数据库。在Spring Boot应用程序中,可以使用Spring Data JPA来简化数据库访问。本文将详细介绍Spring Boot整合Spring Data JPA的详细方法,包…

    Java 2023年5月15日
    00
  • Java xml出现错误 javax.xml.transform.TransformerException: java.lang.NullPointerException

    当Java程序尝试使用javax.xml.transform包中的Transformer类转换XML文档时,有时会出现“javax.xml.transform.TransformerException: java.lang.NullPointerException”错误。这个错误通常表示程序在加载XML文档时遇到了一个空指针异常。以下是解决该问题的步骤和示例…

    Java 2023年5月27日
    00
  • mybatis实现获取入参是List和Map的取值

    对于MyBatis,我们可以通过Mapper接口的方法的入参类型来传递参数。如果我们需要传递List或者Map类型的参数,该如何处理呢?下面我们来一一讲解。 传递List类型的参数 当我们需要将一个List类型的参数传递给Mapper接口的方法时,我们可以采用@Param注解的方式将参数进行命名,如下所示: public interface UserMapp…

    Java 2023年5月20日
    00
  • Java实现读取键盘输入保存到txt文件,再统计并输出每个单词出现次数的方法

    首先,我们需要了解如何从键盘读取输入并保存到txt文件中,接着再通过编程实现统计每个单词出现次数。下面是完整攻略: 1. 从键盘读取输入并保存到txt文件中 我们可以使用Scanner类从键盘获取用户输入,将输入的内容保存到txt文件中。代码如下: import java.io.*; public class Main { public static voi…

    Java 2023年5月26日
    00
  • 如何自定义Java类加载器?

    自定义Java类加载器是Java中非常重要的一项功能,可以实现自己的加载逻辑和自定义的类查找方案,在很多场合下具备重要的应用价值。本文将详细讲解自定义Java类加载器的使用攻略。 目录 Java类加载器 自定义Java类加载器 示例说明一 示例说明二 结语 Java类加载器 在讲解自定义Java类加载器之前,我们需要了解Java类加载器。Java在运行时动态…

    Java 2023年5月11日
    00
  • Java 如何优雅的拷贝对象属性

    当我们需要在 Java 中将一个类的属性值赋值给另一个类时,常见的做法是手动逐个拷贝属性值。但是,这种方法在有大量属性需要拷贝时非常繁琐且容易出错。因此,我们需要一种更优雅的方式来完成对象属性的拷贝,下面是一种实现方式和示例说明。 使用 BeanUtils BeanUtils 是一款常用的 Java 工具包,其中提供了许多方便的工具方法,包括对象属性的复制和…

    Java 2023年5月26日
    00
  • JSP开发入门(四)–JSP的内部对象

    JSP(JavaServer Pages)是一种动态网页开发技术,通过将静态HTML页面和动态Java代码相结合,实现网页的动态化。在JSP的开发过程中,常会用到JSP的内部对象。本文将详细讲解JSP的内部对象。 JSP的内部对象 JSP有9个内部对象,分别是:request、response、out、session、application、page、exc…

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