第一种: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进行测试