1.加入依赖
<!-- springboot-aop包,AOP切面注解,Aspectd等相关注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.新建一个注解,便于切换数据源
/**
* @program: springboot_course
* @description: 多数据源注解
* @author: ChenZhiXiang
* @create: 2019-06-12 09:21
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default "primaryDataSource";
}
3.新建一个类DataSourceContextHolder,用于保存本地数据源
/**
* @program: springboot_course
* @description: 用于保存本地数据源
* @author: ChenZhiXiang
* @create: 2019-06-12 09:24
**/
public class DataSourceContextHolder {
/**
* 默认数据源
*/
public static final String DEFAULT_DS = "primaryDataSource";
/**
* ThreadLocal之后会进行讲解
*/
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
/** 设置数据源名 */
public static void setDB(String dbType) {
System.out.println("切换到{"+dbType+"}数据源");
contextHolder.set(dbType);
}
/** 获取数据源名 */
public static String getDB() {
return (contextHolder.get());
}
/** 清除数据源名 */
public static void clearDB() {
contextHolder.remove();
}
}
4.新建DynamicDataSource类用于获取本地数据源
/**
* @program: springboot_course
* @description: 获取本地数据源
* @author: ChenZhiXiang
* @create: 2019-06-12 09:26
**/
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
System.out.println("数据源为"+DataSourceContextHolder.getDB());
return DataSourceContextHolder.getDB();
}
}
5.新建DataSourceConfig读取配置
/**
* @program: springboot_course
* @description: 多数据源配置类
* @author: ChenZhiXiang
* @create: 2019-06-12 09:27
**/
@Configuration
public class DataSourceConfig {
@Autowired
private Environment env;
/**
* 数据源1
* prefix application.properteis中对应属性的前缀
* @return
*/
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
/**
* 数据源2
* @return
*/
@Bean(name = "secondDataSource")
@ConfigurationProperties(prefix = "spring.datasource.second")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
/**
* 动态数据源: 通过AOP在不同数据源之间动态切换
* @return
*/
@Primary
@Bean(name = "dynamicDataSource")
public DynamicDataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
// 默认数据源
dynamicDataSource.setDefaultTargetDataSource(primaryDataSource());
// 配置多数据源
Map<Object, Object> dsMap = new HashMap();
dsMap.put("primaryDataSource", primaryDataSource());
dsMap.put("secondDataSource", secondDataSource());
dynamicDataSource.setTargetDataSources(dsMap);
return dynamicDataSource;
}
/**
* 根据数据源创建SqlSessionFactory
*/
@Bean
public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception {
SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
// 指定数据源(这个必须有,否则报错)
fb.setDataSource(ds);
// 下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加, 指定基包
fb.setTypeAliasesPackage(env.getProperty("mybatis.type-aliases-package"));
fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapper-locations")));
return fb.getObject();
}
/**
* 配置@Transactional注解事物
* @return
*/
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
6.新建DynamicDataSourceAspect.java类用于自定义注解 + AOP的方式实现数据源动态切换。
/**
* @program: springboot_course
* @description: java类用于自定义注解 + AOP的方式实现数据源动态切换
* @author: ChenZhiXiang
* @create: 2019-06-12 09:31
**/
@Aspect
@Component
public class DynamicDataSourceAspect {
@Pointcut(value = "execution(* com.example.service.*.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void beforeSwitchDS(JoinPoint point){
//获得当前访问的class
Class<?> className = point.getTarget().getClass();
//获得访问的方法名
String methodName = point.getSignature().getName();
//得到方法的参数的类型
Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
String dataSource = DataSourceContextHolder.DEFAULT_DS;
try {
// 得到访问的方法对象
Method method = className.getMethod(methodName, argClass);
// 判断是否存在@DS注解
if (method.isAnnotationPresent(DataSource.class)) {
DataSource annotation = method.getAnnotation(DataSource.class);
// 取出注解中的数据源名
dataSource = annotation.value();
}
} catch (Exception e) {
e.printStackTrace();
}
// 切换数据源
DataSourceContextHolder.setDB(dataSource);
}
@After("pointcut()")
public void afterSwitchDS(JoinPoint point){
DataSourceContextHolder.clearDB();
}
}
7.添加配置文件
yml方式
spring:
datasource:
primaryDataSource:
jdbc-url: jdbc:mysql:/localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=false&failOverReadOnly=false
username: test1
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
secondDataSource:
jdbc-url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&failOverReadOnly=false
username: test2
password: 123456
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
properties方式
spring.datasource.primary.jdbc-url=jdbc:mysql://192.168.0.194:3306/channel-reward?characterEncoding=UTF-8&useSSL=true&serverTimezone=GMT%2B8&useUnicode=true
spring.datasource.primary.username=root
spring.datasource.primary.password=bonc_mysql
spring.datasource.primary.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.second.jdbc-url=jdbc:mysql://localhost:3306/czx?characterEncoding=UTF-8&useSSL=true&serverTimezone=GMT%2B8&useUnicode=true
spring.datasource.second.username=
spring.datasource.second.password=
spring.datasource.second.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.second.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.pojo
8.使用,使用注解自主切换