带你看懂RuoYi动态数据源切换


数据源是什么

数据源,对于java来说,就是可用的数据库,那么我平时开发的springboot springcloud项目,那么也就是yml或者properties中的链接信息, 例如 mysql redis influx mongodb sqlserver clickhouse nebula-graph …
一般在spring中,都已经对其做好了封装


一、spring中是如何处理各种数据源的?

那就不得不说下JdbcTemplate 了,只要是各种遵循了jdbc标准的数据源,也就是大部分的关系型数据库,都是可以通过它来操作的;简直就是神奇~~ 怎么使用呢?

1.开搞springboot

搞一个springboot项目 由于我使用了mysql,所以还引入了mysql驱动包

	  <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-jdbc</artifactId>
      </dependency>
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
         <scope>runtime</scope>
      </dependency>

然后在yml加入相应配置

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://xxxxx:3307/yuque
    username: root
    password: 123456

2.创建一个测试类

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class WordApplicationTests1 {

    @Test
    void contextLoads() {
    }

    @Autowired
    JdbcTemplate jdbcTemplate;

    @SneakyThrows
    @Test
    public void query() {
        List<Bom> bomList = jdbcTemplate.query("select DISTINCT * from bom", new BeanPropertyRowMapper<>(Bom.class));

        System.out.println(JSONUtil.toJsonStr(bomList));
    }
}

相当于可以了,用的就是yml中的配置查询的数据库
在这里插入图片描述

  • 我有一个想法,我想查询一个其他的库的数据,但是之前的yml中的我还想用

改造后,变成了

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class WordApplicationTests1 {

    @Test
    void contextLoads() {
    }

    @Autowired
    JdbcTemplate jdbcTemplate;

    @SneakyThrows
    @Test
    public void query() {
        List<Bom> bomList = jdbcTemplate.query("select DISTINCT * from bom", new BeanPropertyRowMapper<>(Bom.class));

        System.out.println(JSONUtil.toJsonStr(bomList));

        Properties properties = new Properties();
        properties.put("url", "jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true");
        properties.put("username", "root");
        properties.put("driverClassName", "com.mysql.jdbc.Driver");
        properties.put("password", "root");

        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
        JdbcTemplate template = new JdbcTemplate(dataSource);

        List<Bom> list = template.query("select * from bom", new BeanPropertyRowMapper<>(Bom.class));
        System.out.println(JSONUtil.toJsonStr(list));
    }
}

还是能用的,两个都能查询出数据
在这里插入图片描述
那…请小伙伴思考下,如果是用jdbc弄一个动态数据源,是不是也不是很难,我需要用哪个库的信息,就让他加载哪个库的配置信息就ok了呀.对吧?
甚至,我可以将配置信息放入数据库中,启动后,一次性加载到内存,并实例化相应的datasource 实例,然后在实例化相应的jdbctemplete,放入到的全局中,那么我就可以自如切换了!!!

二、有了如上的理论,那么想想动态切换数据源吧

参考若依的动态数据源配置

若依
大体思路如下:

  • 首先利用本地线程搞一个缓存,目的是为了存放当前可用的数据源,这样就可以设置/移除 某个数据源了;
DynamicDataSourceContextHolder 仅仅是个缓存
  • 由于为了使用方便,所以他自定义了注解,用来切换数据源,也就是更改上面的当前线程缓存,那么自定义之后,就需要通过切面去实现这个自定义的注解,里面的中心思想就是获取传入的可用数据源(可能有多个),替换之为当前数据源(只能有一个);
DataSourceAspect 切面实现切换
  • 那么多个数据源是从哪里来的呢,是在项目启动的时候,他就已经把可用数据源都实例化好了,然后存放起来了,就像我之前分析的那样,关键点就是 实现这个方法 AbstractRoutingDataSource 其中 放入一个map 就是数据源本尊了
DruidConfig 把所有数据源都加载进去了
  • 之后就可以通过map.getkey 那样,获取到自己想要的数据源了;然后更改本地线程的数据源
  • 切换之后,查询的时候,就会重新查询到当前设置后的数据源,然后再去查询
  • 为啥用ThreadLocal呢? 因为我只想针对此次查询修改为其他数据源有效,此次结束之后,当前线程销毁;下次查询不指定的情况下默认仍然是原来的数据源,否则将就此改变了整个项目的数据源;

重点中的重点

DynamicDataSource extends AbstractRoutingDataSource

@Override
   protected Object determineCurrentLookupKey(){
       return DynamicDataSourceContextHolder.getDataSourceType();// 每次执行都会重新获取新值
   }

在这里插入图片描述


总结

通过此次JdbcTemplate 的数据源切换,想到了之前看过的若依项目中的多数据源切换问题,这次带着我自己的想法去看,果然再次阅读,收获颇丰;算是彻底看懂了吧;
希望我的理解能为你带来启发;
当然现在已经有了dynamic-datasource-spring-boot-starter 这样的多数据start 完成了类似的功能,但是看看之前的,也能对于它有更好的理解;相当于自己手写了一个简易的 dynamic-datasource-spring-boot-starter

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
对于ruoyi多数据源配置SQL Server,你可以按照以下步骤进行操作: 1. 在ruoyi-generator模块的resources目录下的application.yml文件中,针对每个数据源配置相关信息,如下所示: ``` spring: datasource: # 主数据源配置 primary: url: jdbc:mysql://localhost:3306/primary?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver # 第二个数据源配置 secondary: url: jdbc:sqlserver://localhost:1433;databaseName=secondary username: sa password: password driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver ``` 2. 在ruoyi-admin模块的pom.xml文件中,添加SQL Server数据库驱动依赖,如下所示: ```xml <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <version>8.4.1.jre8</version> </dependency> ``` 3. 在ruoyi-admin模块的src/main/java/com/ruoyi/framework/config目录下,创建一个新的数据源配置类,如下所示: ```java @Configuration public class SecondaryDataSourceConfig { @Bean(name = "secondaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondarySqlSessionFactory") public SqlSessionFactory secondarySqlSessionFactory(@Qualifier("secondaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); // 设置其他配置,例如mapper文件所在路径等 return bean.getObject(); } @Bean(name = "secondarySqlSessionTemplate") public SqlSessionTemplate secondarySqlSessionTemplate(@Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } // 可以根据需要配置其他的数据源 } ``` 4. 在ruoyi-admin模块的src/main/java/com/ruoyi/framework/config目录下,创建一个新的数据源配置类,如下所示: ```java @Configuration public class DataSourceConfig { @Primary @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Primary @Bean(name = "primarySqlSessionFactory") public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); // 设置其他配置,例如mapper文件所在路径等 return bean.getObject(); } @Primary @Bean(name = "primarySqlSessionTemplate") public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } // 可以根据需要配置其他的数据源 } ``` 5. 在ruoyi-admin模块的src/main/java/com/ruoyi/framework/config目录下,创建一个新的数据源配置类,如下所示: ```java @Configuration public class DynamicDataSourceConfig { @Bean public DynamicDataSource dataSource(@Qualifier("primaryDataSource") DataSource primaryDataSource, @Qualifier("secondaryDataSource") DataSource secondaryDataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DatabaseType.PRIMARY, primaryDataSource); targetDataSources.put(DatabaseType.SECONDARY, secondaryDataSource); DynamicDataSource dataSource = new DynamicDataSource(); dataSource.setTargetDataSources(targetDataSources); dataSource.setDefaultTargetDataSource(primaryDataSource); return dataSource; } @Bean public SqlSessionFactory sqlSessionFactory(DynamicDataSource dataSource) throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); // 设置其他配置,例如mapper文件所在路径等 return sessionFactory.getObject(); } @Bean public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } // 可以根据需要配置其他的数据源 } ``` 6. 在ruoyi-admin模块的src/main/java/com/ruoyi/common/enums目录下,创建一个新的枚举类DatabaseType.java,如下所示: ```java public enum DatabaseType { PRIMARY, SECONDARY; } ``` 7. 在ruoyi-admin模块的src/main/java/com/ruoyi/datasource目录下,创建一个新的动态数据源类DynamicDataSource.java,如下所示: ```java public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DatabaseContextHolder.getDatabaseType(); } } ``` 8. 在ruoyi-admin模块的src/main/java/com/ruoyi/datasource目录下,创建一个新的数据源上下文类DatabaseContextHolder.java,如下所示: ```java public class DatabaseContextHolder { private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>(); public static void setDatabaseType(DatabaseType databaseType) { contextHolder.set(databaseType); } public static DatabaseType getDatabaseType() { return contextHolder.get(); } public static void clearDatabaseType() { contextHolder.remove(); } } ``` 9. 在ruoyi-admin模块的src/main/java/com/ruoyi/datasource目录下,创建一个新的数据源切换类DataSourceAspect.java,如下所示: ```java @Aspect @Component public class DataSourceAspect { @Before("@annotation(com.ruoyi.common.annotation.DataSource)") public void switchDataSource(JoinPoint point) { MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); DataSource dataSource = method.getAnnotation(DataSource.class); if (dataSource != null) { DatabaseContextHolder.setDatabaseType(dataSource.value()); } } @After("@annotation(com.ruoyi.common.annotation.DataSource)") public void restoreDataSource(JoinPoint point) { DatabaseContextHolder.clearDatabaseType(); } } ``` 10. 在ruoyi-admin模块的src/main/java/com/ruoyi/common/annotation目录下,创建一个新的注解类DataSource.java,如下所示: ```java @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { DatabaseType value() default DatabaseType.PRIMARY; } ``` 11. 配置完成后,可以在需要切换数据源的service或mapper方法上,使用@DataSource注解来指定数据源,例如: ```java @DataSource(DatabaseType.SECONDARY) public List<User> listUsers() { return userMapper.listUsers(); } ``` 请注意,在进行多数据源配置时,请确保你的ruoyi版本支持多数据源功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寂寞旅行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值