jm-apis-common 更改druid
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
配置中心 jm-datasource.yaml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
master:
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/db_jm_example?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useUnicode=true&rewriteBatchedStatements=true
slave:
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/db_jm_example_log?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useUnicode=true&rewriteBatchedStatements=true
启动类排除DataSourceAutoConfiguration.class
package com.jm;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class JmUser {
public static void main(String[] args) {
SpringApplication.run(JmUser.class, args);
}
}
jm-apis-common-conf 多数据源配置
package com.jm.common.conf.datasource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DynamicDataSourceConf {
@Primary
@Bean
@ConfigurationProperties("spring.datasource.druid.master")
public DataSource masterDatasource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.druid.slave")
public DataSource slaveDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DynamicDataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>(2);
targetDataSources.put("master", masterDatasource());
targetDataSources.put("slave", slaveDataSource());
dynamicDataSource.setDefaultTargetDataSource(masterDatasource());
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource());
return sqlSessionFactoryBean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate() throws Exception {
return new SqlSessionTemplate(sqlSessionFactory());
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dynamicDataSource());
}
}
继承AbstractRoutingDataSource 实现动态数据源切换
package com.jm.common.conf.datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
@Override
protected Object determineCurrentLookupKey() {
return get();
}
public static void set(String dataSource) {
CONTEXT_HOLDER.set(dataSource);
}
public static String get() {
return CONTEXT_HOLDER.get();
}
public static void clear() {
CONTEXT_HOLDER.remove();
}
}
定义切换数据源注解
package com.jm.common.conf.datasource;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DS {
String name() default "master";
}
定义@ds注解切面
package com.jm.common.conf.datasource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("@annotation(com.jm.common.conf.datasource.DS)")
public void pointCut() {
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
DS dataSource = method.getAnnotation(DS.class);
if (dataSource == null) {
DynamicDataSource.set("master");
} else {
DynamicDataSource.set(dataSource.name());
}
try {
return point.proceed();
} finally {
DynamicDataSource.clear();
}
}
}
测试实现
package com.jm.service.impl;
import com.jm.common.conf.datasource.DynamicDataSource;
import com.jm.common.conf.exception.ErrorException;
import com.jm.model.SysUser;
import com.jm.service.i.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Slf4j
public class TestDsService {
private final SysUserService userService;
@Autowired
public TestDsService(SysUserService userService) {
this.userService = userService;
}
@Transactional(rollbackFor = Exception.class)
public void test() {
DynamicDataSource.set("slave");
this.test1();
DynamicDataSource.set("master");
this.test2();
throw new ErrorException("");
}
private void test2() {
this.userService.save(new SysUser().setUsername("master"));
}
private void test1() {
this.userService.save(new SysUser().setUsername("slave"));
}
}
完整代码请看项目 git地址
https://gitee.com/sunuping/jianmu-example-jdk17.git