spring boot 项目如需实现多数据源,进行简单的配置即可
application.yml 文件配置
spring:
datasource:
primary: #主数据源
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://xxxxxxx:3306/car?characterEncoding=utf8&serverTimezone=GMT%2B8
username: root
password: root
secondary: #从数据源
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://xxxxxxx:3306/car?characterEncoding=utf8&serverTimezone=GMT%2B8
username: root
password: password
目标数据源注解,注解在方法上指定数据源的名称
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
//此处接收数据源名称
String value();
}
数据源切面的配置,我这里是在mapper标注访问不同数据源
@Aspect
@Component
public class DataSourceAspect {
private static Logger logger = LogManager.getLogger(DataSourceAspect.class.getName());
//切入点在service层的方法上,配置aop的切入点
@Pointcut("execution( * com.xxxx.mapper.*.*(..))")
public void dataSourcePointCut() {
}
//切入点只对@Service注解的类上的@DataSource方法生效
// @Pointcut(value="@within(org.springframework.stereotype.Service) && @annotation(dataSource)" )
// public void dataSourcePointCut(DataSource dataSource) {
// }
@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(DataSource.class)) {
DataSource annotation = m.getAnnotation(DataSource.class);
String dataSourceName = annotation.value();
DynamicDataSourceHolder.putDataSouce(dataSourceName);
logger.debug("-----current thread " + Thread.currentThread().getName() + " add " + dataSourceName + " to ThreadLocal-----");
} else {
logger.debug("switch datasource fail, use default");
}
} catch (NoSuchMethodException e) {
logger.error("current thread " + Thread.currentThread().getName() + " add data to ThreadLocal error", e);
}
}
//执行完切面后,清空线程共享中的数据源名称
@After("dataSourcePointCut()")
public void after(JoinPoint joinPoint){
DynamicDataSourceHolder.removeDataSource();
}
}
动态数据源实现类
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {
//数据源路由,用于产生要选取的数据源逻辑名称
@Override
protected Object determineCurrentLookupKey() {
//从线程共享中获取数据源名称
return DynamicDataSourceHolder.getDataSource();
}
}
数据源配置,我这里是只配置了两个
@Configuration
@EnableScheduling
@Slf4j
public class DataSourceConfig {
@Autowired
private DBProperties dbProperties;
/**
* 设置动态数据源,通过@Primary 来确定主DataSource
*/
@Bean(name = "dataSource")
public DynamicDataSource dataSource(){
DynamicDataSource dynamicDataSource = new DynamicDataSource();
//1.设置默认数据源
dynamicDataSource.setDefaultTargetDataSource(dbProperties.getPrimary());
//2.配置多数据源
Map<Object, Object> map = new HashMap<>();
map.put("primary", dbProperties.getPrimary());
map.put("secondary", dbProperties.getSecondary());
//3.存放数据源集
dynamicDataSource.setTargetDataSources(map);
return dynamicDataSource;
}
}
动态数据源持有者,负责利用ThreadLocal存取数据源名称
public class DynamicDataSourceHolder {
//本地线程共享对象
private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();
public static void putDataSouce(String name){
THREAD_LOCAL.set(name);
}
public static String getDataSource(){
return THREAD_LOCAL.get();
}
public static void removeDataSource(){
THREAD_LOCAL.remove();
}
}
数据源实体类
@Component
@Data
@ConfigurationProperties(prefix = "spring.datasource")
public class DBProperties {
private HikariDataSource primary;
private HikariDataSource secondary;
public HikariDataSource getPrimary() {
return primary;
}
public void setPrimary(HikariDataSource primary) {
this.primary = primary;
}
public HikariDataSource getSecondary() {
return secondary;
}
public void setSecondary(HikariDataSource secondary) {
this.secondary = secondary;
}
}
测试实现,在mapper中指定不同数据源
@DataSource("primary")
List<Agent> getPrimary();
@DataSource("secondary")
List<Agent> getSecondary();
启动项目访问接口,即可获取不同数据源的数据
本文详细介绍了如何在SpringBoot项目中配置和使用多数据源,包括application.yml配置、数据源注解、数据源切面配置、动态数据源实现等关键步骤。通过具体示例展示了如何在mapper层指定不同数据源,实现数据源的灵活切换。
1877

被折叠的 条评论
为什么被折叠?



