版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangxing52077/article/details/81236943
1.场景还原
在实际项目中,一个工程配置多个数据源很常见,工程可能会根据业务或者模块访问不同的数据库或表;今天笔者就springboot中配置多数据源作个详细的讲解
2.实现方案
注意:一个应用工程中有且只有一个启动类,其依赖的模块不能是带有启动类的模块
①application.yml配置
spring:
datasource:
druid:
master: #数据源1
url: jdbc:mysql://xxxx1:3306/online_test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
username: root
password: root
slave: #数据源2
url: jdbc:mysql://xxxxx2:3306/online_test?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
username: root
password: root
driverClassName: com.mysql.jdbc.Driver
#最大活跃数
maxActive: 20
#初始化数量
initialSize: 1
#最大连接等待超时时间
maxWait: 60000
#打开PSCache,并且指定每个连接PSCache的大小
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
#通过connectionProperties属性来打开mergeSql功能;慢SQL记录
#connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 1 from dual
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
#配置监控统计拦截的filters,去掉后监控界面sql将无法统计,'wall'用于防火墙
filters: stat, wall, log4j
②pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
③自定义多数据源注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String name() default "";
}
④多数据源切面处理类,实现数据库的选择
@Aspect
@Component
@Slf4j
public class DataSourceAspect implements Ordered {
@Pointcut("@annotation(com.yivi.yivisender.dispatchorder.conf.datasources.annotation.DataSource)")
public void dataSourcePointCut() {
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
DataSource ds = method.getAnnotation(DataSource.class);
if(ds == null){
DynamicDataSource.setDataSource(DataSourceNames.MASTER);
log.debug("set datasource is " + DataSourceNames.MASTER);
}else {
DynamicDataSource.setDataSource(ds.name());
log.debug("set datasource is " + ds.name());
}
try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSource();
log.debug("clean datasource");
}
}
@Override
public int getOrder() {
return 1;
}
}
public interface DataSourceNames {
String MASTER = "master";
String SLAVE = "slave";
}
⑤DynamicDataSource的申明,其作为工程全局的datasource使用
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}
⑥动态数据源的配置
@Configuration
public class DynamicDataSourceConfig {
@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 dataSource(DataSource masterDataSource, DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceNames.MASTER, masterDataSource);
targetDataSources.put(DataSourceNames.SLAVE, slaveDataSource);
return new DynamicDataSource(masterDataSource, targetDataSources);
}
}
⑦启动类的配置
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
@Import({DynamicDataSourceConfig.class})
@ComponentScan("com.yivi")
@MapperScan({"com.yivi.yivisender.dispatchorder.dao","com.yivi.yivisender.dispatchdata.dao","com.yivi.yivisender.dispatchcalengine.dao"})
public class DispatchorderApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(DispatchorderApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(DispatchorderApplication.class);
}
}
3.测试效果
①多数据源测试类
扫描二维码关注公众号,回复:
3019802 查看本文章
@Service
public class DynasticServiceTest {
@Autowired
private YiViUserAccountMapper yiViUserAccountMapper;
@DataSource(name = DataSourceNames.MASTER)
public int addToMaster(String account ,String userId){
return yiViUserAccountMapper.increaseAccount(account,userId);
}
@DataSource(name = DataSourceNames.SLAVE)
public int addToSlave(String account ,String userId){
return yiViUserAccountMapper.increaseAccount(account,userId);
}
}
②测试主库插入
③测试从库插入
好了,我是张星,欢迎加入博主技术交流群,群号:526601468