java 动态切换数据源方式_java springboot动态切换数据源oracle+mysql

添加了 @Transactional 的方法因为在 Service 层开启了事务,

会在事务结束之后才会切换数据源,所以加了@Transactional不生效

1.添加是数据源

package com.portal.config.datasource;

import java.lang.annotation.*;

/**

* @author pei

*/

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface DataSource {

String name() default "";

}

2.数据源切面

package com.portal.config.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.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.core.Ordered;

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**

* @author pei

* @since 2020-12-28 15:46

*/

@Aspect

@Component

public class DataSourceAspect implements Ordered {

protected Logger logger = LoggerFactory.getLogger(getClass());

@Pointcut("@annotation(com.portal.config.datasource.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.FIRST);

logger.info("数据源: " + DataSourceNames.FIRST);

}else {

DynamicDataSource.setDataSource(ds.name());

logger.info("数据源: " + ds.name());

}

try {

return point.proceed();

} finally {

DynamicDataSource.clearDataSource();

logger.info("清除数据源");

}

}

@Override

public int getOrder() {

return 1;

}

}

3.数据源枚举

package com.portal.config.datasource;

public interface DataSourceNames {

String FIRST = "first";

String SECOND = "second";

}

4.动态管理数据源

package com.portal.config.datasource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;

import java.util.Map;

/**

* @author pei

* @since 2020-12-28 15:44

*/

public class DynamicDataSource extends AbstractRoutingDataSource {

private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();

public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) {

super.setDefaultTargetDataSource(defaultTargetDataSource);

super.setTargetDataSources(targetDataSources);

super.afterPropertiesSet();

}

@Override

protected Object determineCurrentLookupKey() {

return getDataSource();

}

public static void setDataSource(String dataSource) {

CONTEXT_HOLDER.set(dataSource);

}

public static String getDataSource() {

return CONTEXT_HOLDER.get();

}

public static void clearDataSource() {

CONTEXT_HOLDER.remove();

}

}

5.注入配置

package com.portal.config.datasource;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;

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 javax.sql.DataSource;

import java.util.HashMap;

import java.util.Map;

/**

* @author pei

* @since 2020-12-28 15:43

*/

@Configuration

public class DynamicDataSourceConfig {

@Bean

@ConfigurationProperties("spring.datasource.druid.first")

public DataSource firstDataSource(){

return DruidDataSourceBuilder.create().build();

}

@Bean

@ConfigurationProperties("spring.datasource.druid.second")

public DataSource secondDataSource(){

return DruidDataSourceBuilder.create().build();

}

@Bean

@Primary

public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource) {

Map targetDataSources = new HashMap<>();

targetDataSources.put(DataSourceNames.FIRST, firstDataSource);

targetDataSources.put(DataSourceNames.SECOND, secondDataSource);

return new DynamicDataSource(firstDataSource, targetDataSources);

}

}

6.配置

datasource:

druid:

first:

type: com.alibaba.druid.pool.DruidDataSource

driverClassName: com.mysql.jdbc.Driver

url: jdbc:mysql://127.0.0.1:3306/cz_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8

username: root

password: root

second:

url: jdbc:oracle:thin:@127.0.0.1:1521:orcl

username: root

password: root

driver-class-name: oracle.jdbc.driver.OracleDriver

initial-size: 10

max-active: 100

min-idle: 10

max-wait: 60000

pool-prepared-statements: true

max-pool-prepared-statement-per-connection-size: 20

time-between-eviction-runs-millis: 60000

min-evictable-idle-time-millis: 300000

#Oracle需要打开注释

#validation-query: SELECT 1 FROM DUAL

test-while-idle: true

test-on-borrow: false

test-on-return: false

stat-view-servlet:

enabled: true

url-pattern: /druid/*

#login-username: admin

#login-password: admin

filter:

stat:

log-slow-sql: true

slow-sql-millis: 1000

merge-sql: false

wall:

config:

multi-statement-allow: true

好的,你的问题是关于如何在Spring Boot应用中实现多数据源动态切换,使用的技术包括Spring Boot、MyBatis、MySQLOracle、Druid数据源连接池、自定义注解和切面,并且配置文件使用application.yml格式。 首先,需要在pom.xml文件中添加相应的依赖: ```xml <!--Spring Boot--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--MyBatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <!--MySQL--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency> <!--Oracle--> <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc8</artifactId> <version>19.3.0.0</version> </dependency> <!--Druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.6</version> </dependency> ``` 接下来,需要在application.yml文件中配置数据源和MyBatis相关的属性,例如: ```yaml spring: datasource: druid: # 数据源1 db1: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root # 数据源2 db2: driver-class-name: oracle.jdbc.OracleDriver url: jdbc:oracle:thin:@localhost:1521:ORCL username: scott password: tiger # 默认数据源 url: jdbc:mysql://localhost:3306/db1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.demo.entity ``` 然后,需要定义一个自定义注解,用于标识哪些方法需要使用哪个数据源: ```java @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { String value() default "db1"; } ``` 在数据源切换的时候,我们需要获取注解上指定的数据源名称,因此需要定义一个切面: ```java @Aspect @Component public class DataSourceAspect { @Around("@annotation(ds)") public Object around(ProceedingJoinPoint point, DataSource ds) throws Throwable { String dataSourceName = ds.value(); DynamicDataSource.setDataSource(dataSourceName); try { return point.proceed(); } finally { DynamicDataSource.clearDataSource(); } } } ``` 最后,需要定义一个动态数据源,用于实现数据源切换: ```java public class DynamicDataSource extends AbstractRoutingDataSource { private static final ThreadLocal<String> dataSourceHolder = new ThreadLocal<>(); @Override protected Object determineCurrentLookupKey() { return dataSourceHolder.get(); } public static void setDataSource(String dataSourceName) { dataSourceHolder.set(dataSourceName); } public static void clearDataSource() { dataSourceHolder.remove(); } } ``` 至此,多数据源动态切换的配置就完成了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值