🍰SpringBoot下动态数据源切换
第一种:Mybatis-Plus的dynamic-datasource
Gitee地址:https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter
要实现其实很简单,一个注解就可以了
1、创建两个一库,一样的表进行测试
2、搭建SpringBoot引入dynamic-datasource依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.6.1</version> </dependency>
3、修改SpringBoot配置
spring: datasource: dynamic: primary: master #设置默认的数据源或者数据源组,默认值即为master strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 datasource: master: url: jdbc:mysql://localhost:3306/datasource-1?serverTimezone=UTC username: root password: xxx driver-class-name: com.mysql.cj.jdbc.Driver slave_1: url: jdbc:mysql://localhost:3306/datasource-2?serverTimezone=UTC username: root password: xxx driver-class-name: com.mysql.cj.jdbc.Driver
4、在方法上面添加@DS注解
第二种:使用Aop自己实现动态数据源的切换
Git地址:https://gitee.com/zhang-zhixi/dynamic-datasource-springboot
1、创建两个一库,一样的表进行测试
2、搭建SpringBoot环境
3、自定义切换数据源注解
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface UsingDataSource { String value() default ""; }
4、编写存储自定义数据源的容器
/** * @author zhixi * 存储数据源的key,使用线程安全方式进行添加数据源 */ public class DataSourceContextHolder { public static ThreadLocal<String> key = new ThreadLocal<>(); public static void setKey(String key) { DataSourceContextHolder.key.set(key); } public static String getKey() { return key.get(); } public static void clearKey() { key.remove(); } }
5、确定使用的数据源
/** * @author zhixi * AbstractRoutingDataSource是一个抽象类,是Spring提供的用于动态数据源切换的类。 */ public class DynamicDataSource extends AbstractRoutingDataSource { /** * 查找哪个数据源的时候使用的key,该方法用于确定当前数据源 * @return 数据源 */ @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getKey(); } }
6、重写Spring相关配置
package com.zhixi.config; import com.zhixi.datasource.DynamicDataSource; import org.mybatis.spring.SqlSessionFactoryBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import javax.sql.DataSource; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * @author zhixi * Spring相关配置 */ @Configuration public class DataSourceConfig { /** * 为每个数据源单独设置一个Bean * * @return 数据源1 */ @ConfigurationProperties("datasource1") @Bean public DataSource dataSource1() { return DataSourceBuilder.create().build(); } /** * 为每个数据源单独设置一个Bean * * @return 数据源2 */ @Bean @ConfigurationProperties("datasource2") public DataSource dataSource2() { return DataSourceBuilder.create().build(); } /** * 添加数据源 * * @return 自定义数据源 */ @Bean public DynamicDataSource dynamicDataSource() { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put("ds1", dataSource1()); targetDataSources.put("ds2", dataSource2()); DynamicDataSource dynamicDataSource = new DynamicDataSource(); // 设置目标数据源 dynamicDataSource.setTargetDataSources(targetDataSources); // 设置默认目标数据源 dynamicDataSource.setDefaultTargetDataSource(dataSource1()); return dynamicDataSource; } /** * 使用DynamicDataSource作为数据源。 * * @param dynamicDataSource 数据源 * @return 配置好的SqlSessionFactoryBean对象,以便将其用作MyBatis框架的数据源。 * @throws IOException 异常 */ @Bean public SqlSessionFactoryBean sqlSessionFactoryBean(DynamicDataSource dynamicDataSource) throws IOException { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); /*设置mybatis configuration 扫描路径 */ PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); //加载配置文件的地址 bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml")); bean.setDataSource(dynamicDataSource); return bean; } /** * 使用返回的数据源创建一个DataSourceTransactionManager对象。 * DataSourceTransactionManager是Spring提供的事务管理器,用于管理基于数据源的事务 * @return 事务管理器 */ @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dynamicDataSource()); } }
7、使用AOP,在方法调用前设置使用的数据源
package com.zhixi.datasource; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * @author zhixi * Aop切面,对注解进行切面 */ @Aspect @Component public class DataSourceAspect { @Pointcut("@annotation(com.zhixi.datasource.UsingDataSource)") public void checkPointCut() { } /** * 方法调用之前设置数据源 * @param usingDataSource 拿到注解的数据源的值 */ @Before("checkPointCut() && @annotation(usingDataSource)") public void checkBefore(UsingDataSource usingDataSource) { // 添加数据源的key DataSourceContextHolder.setKey(usingDataSource.value()); } @After("checkPointCut()") public void checkAfter() { DataSourceContextHolder.clearKey(); } }
8、启动类配置
/** * @author zhixi * exclude = {DataSourceAutoConfiguration.class}:排除SpringBoot自带的数据源配置 * EnableAspectJAutoProxy:启动动态代理 */ @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) @MapperScan("com.zhixi.mapper") @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class DynamicDatasourceSpringbootApplication { public static void main(String[] args) { SpringApplication.run(DynamicDatasourceSpringbootApplication.class, args); } }
9、编写Controller进行测试