SpringBoot 2.0+ 开始推 HikariCP ,将默认的数据库连接池从 tomcat jdbc pool 改为了 hikari , HikariCP 在性能和并发方面表现更好一些
yml配置:
#数据源配置
datasource:
dsa:
driver-class-name: com.sybase.jdbc4.jdbc.SybDataSource
jdbc-url: jdbc:sybase:Tds:127.0.0.1:5127/test
type: com.zaxxer.hikari.HikariDataSource
username: root
password: root
dsb:
driver-class-name: com.sybase.jdbc4.jdbc.SybDataSource
jdbc-url: jdbc:sybase:Tds:127.0.0.1:5127/test
type: com.zaxxer.hikari.HikariDataSource
username: root
password: root
com.zaxxer.hikari.HikariDataSource 包为mybatis自带
导入以下依赖
1.创建DBProperties
import com.zaxxer.hikari.HikariDataSource;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 实际数据源配置
*/
@Component
@Data
@ConfigurationProperties(prefix ="spring.datasource")
public class DBProperties {
private HikariDataSourcedsa;
private HikariDataSourcedsc;
private HikariDataSourcedsb;
}
2.创建dataSource
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* 数据源配置
*/
@Configuration
@EnableScheduling
@Slf4j
public class DataSourceConfig {
@Autowired
private DBPropertiesproperties;
@Bean(name ="dataSource")
public DataSourcedataSource() {
//按照目标数据源名称和目标数据源对象的映射存放在Map中
Map targetDataSources =new HashMap<>();
targetDataSources.put("dsa", properties.getDsa());
targetDataSources.put("dsb", properties.getDsb());
targetDataSources.put("dsc", properties.getDsc());
//采用是想AbstractRoutingDataSource的对象包装多数据源
DynamicDataSource dataSource =new DynamicDataSource();
dataSource.setTargetDataSources(targetDataSources);
dataSource.setDefaultTargetDataSource(properties.getDsb());
return dataSource;
}
@Bean
public PlatformTransactionManagertxManager() {
return new DataSourceTransactionManager(dataSource());
}
}
3.创建DynamicDataSource
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 动态数据源实现类
*/
@Slf4j
public class DynamicDataSourceextends AbstractRoutingDataSource {
//数据源路由,此方用于产生要选取的数据源逻辑名称
@Override
protected ObjectdetermineCurrentLookupKey() {
//从共享线程中获取数据源名称
return DynamicDataSourceHolder.getDataSource();
}
}
4.创建DynamicDataSourceHolder
/**
* 动态数据源持有者,负责利用ThreadLocal存取数据源名称
*/
public class DynamicDataSourceHolder {
/**
* 本地线程共享对象
*/
private static final ThreadLocalTHREAD_LOCAL =new ThreadLocal<>();
public static void putDataSource(String name) {
THREAD_LOCAL.set(name);
}
public static StringgetDataSource() {
return THREAD_LOCAL.get();
}
public static void removeDataSource() {
THREAD_LOCAL.remove();
}
}
5.创建TargetDataSource
import java.lang.annotation.*;
/**
* 目标数据源注解,注解在方法上指定数据源的名称
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface TargetDataSource {
Stringvalue();//此处接收的是数据源的名称
}
6.创建DataSourceAspect
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
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.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* 数据源AOP切面定义
*/
@Component
@Aspect
@Slf4j
public class DataSourceAspect {
//切换放在mapper接口的方法上,所以这里要配置AOP切面的切入点
@Pointcut("execution( * com.wondersgroup.yilian.largescreen_interface.dao.*.*(..))")
public void dataSourcePointCut() {
}
@Before("dataSourcePointCut()")
public void before(JoinPoint joinPoint) {
Object target = joinPoint.getTarget();
String method = joinPoint.getSignature().getName();
Class[] clazz = target.getClass().getInterfaces();
Class[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
try {
Method m = clazz[0].getMethod(method, parameterTypes);
//如果方法上存在切换数据源的注解,则根据注解内容进行数据源切换
if (m !=null && m.isAnnotationPresent(TargetDataSource.class)) {
TargetDataSource data = m.getAnnotation(TargetDataSource.class);
String dataSourceName = data.value();
DynamicDataSourceHolder.putDataSource(dataSourceName);
//log.debug("current thread " + Thread.currentThread().getName() + " add " + dataSourceName + " to ThreadLocal");
}else {
//log.debug("switch datasource fail,use default");
}
}catch (Exception e) {
//log.error("current thread " + Thread.currentThread().getName() + " add data to ThreadLocal error", e);
}
}
//执行完切面后,将线程共享中的数据源名称清空
@After("dataSourcePointCut()")
public void after(JoinPoint joinPoint){
DynamicDataSourceHolder.removeDataSource();
}
}
最后将自定义注解@TargetDataSource("dsa")根据不同的连接放在DAO层方法上。
(切记,如果在业务层加了事务,数据源将无法切换)