springboot+mybatis+druid动态数据源

目录

1:使用动态数据源的初衷

2:导入所需要的jar

3:在bootstrap.yml(application.properteis)或者application.yml中写入配置

4:定义DynamicDataSource类,用来动态连接数据源

5:定义DynamicDataSourceConfig,数据源的配置类

6:写一个用来切换数据源的注解类DS

7:写一个AOP类DynamicDataSourceAspect,用来控制数据源切换


1:使用动态数据源的初衷

是能在应用层做到读写分离,即在程序代码中控制不同的查询方法去连接不同的库。除了这种方法以外,数据库中间件也是个不错的选择,它的优点是数据库集群对应用来说只暴露为单库,不需要切换数据源的代码逻辑。

思路:从动态数据源工具中获取到DataSource标示,根据标示获取DataSrouce对象。在Spring容器中,这一点其实更好实现。原理就是在DB访问之前,切换数据源。

***我们通过自定义注解 + AOP的方式实现数据源动态切换。

2:导入所需要的jar

<dependency> <!-- MySql驱动 -->
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>
<dependency> <!-- 连接池 -->
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.9</version>
</dependency>

3:在bootstrap.yml(application.properteis)或者application.yml中写入配置

# 数据源配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      center:
        username: root
        password: root
        url: jdbc:mysql://127.0.0.1:3306/test1?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true
        
      duanguo:
        username: root
        password: root
        url: jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&allowMultiQueries=true&allowPublicKeyRetrieval=true

4:定义DynamicDataSource类,用来动态连接数据源

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.util.Map;

/**
 * Created by xz_10086
 * 2022/6/15 0015 18:35
 * 动态数据源
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
	public static final Logger log= LoggerFactory.getLogger(DynamicDataSource.class);
    //用来装载需要使用的数据源的线程名(即即将调用的数据源线程名变量)
	private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

	/**
	 * 配置DataSource, defaultTargetDataSource为主数据库
	 */
	public DynamicDataSource(DataSource defaultDataSource, Map<Object, Object> dataSources) {
		super.setDefaultTargetDataSource(defaultDataSource);
		super.setTargetDataSources(dataSources);
		super.afterPropertiesSet();
	}

	@Override
	protected Object determineCurrentLookupKey() {
		return getDataSource();
	}

	public static void setDataSource(String dataSource) {
		log.warn("切换数据源为:{}",dataSource);
		contextHolder.set(dataSource);
	}

	public static String getDataSource() {
		return contextHolder.get();
	}

	public static void clearDataSource() {
		contextHolder.remove();
	}

}

5:定义DynamicDataSourceConfig,数据源的配置类

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.spring.cloud.api.util.DynamicDataSource;
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;

/**
 * Created by xz_10086
 * 2022/6/15 0015 18:28
 */
@Configuration
public class DynamicDataSourceConfig {

	@Bean
	@ConfigurationProperties(prefix = "spring.datasource.druid.center") // application.yml中对应属性的前缀
	public DataSource dataSource1() {
		return DruidDataSourceBuilder.create().build();
	}


	@Bean
	@ConfigurationProperties(prefix = "spring.datasource.druid.duanguo") // application.yml中对应属性的前缀
	public DataSource dataSource2() {
		return DruidDataSourceBuilder.create().build();
	}

	@Bean
	@Primary
	public DynamicDataSource dataSource() {
		Map<Object, Object> dataSources = new HashMap<>(2);
		dataSources.put("centerDS", dataSource1());
		dataSources.put("duanguoDS", dataSource2());
		// 还有数据源,在dataSources中继续添加
		System.out.println("DataSources:" + dataSources);
        //参数1为默认数据源,参数2为多数据源集合
		return new DynamicDataSource(dataSource1(), dataSources);
	}
}

6:写一个用来切换数据源的注解类DS

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({
		ElementType.METHOD
})
public @interface DS {
    //设置默认数据源
	String value() default "centerDS";
}

7:写一个AOP类DynamicDataSourceAspect,用来控制数据源切换

import com.spring.cloud.api.annotation.DS;
import com.spring.cloud.api.util.DynamicDataSource;
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.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * Created by xz_10086
 * 2022/6/15 0015 19:04
 */
@Aspect
@Component
public class DynamicDataSourceAspect {
	@Before("@annotation(com.spring.cloud.api.annotation.DS)")
	public void beforeSwitchDS(JoinPoint point){

		//获得当前访问的class
		Class<?> className = point.getTarget().getClass();

		//获得访问的方法名
		String methodName = point.getSignature().getName();
		//得到方法的参数的类型
		Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();
		//默认数据源
		String dataSource = "centerDS";
		try {
			// 得到访问的方法对象
			Method method = className.getMethod(methodName, argClass);

			// 判断是否存在@DS注解
			if (method.isAnnotationPresent(DS.class)) {
				DS annotation = method.getAnnotation(DS.class);
				// 取出注解中的数据源名
				dataSource = annotation.value();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		// 切换数据源
		DynamicDataSource.setDataSource(dataSource);

	}

	//接口调用结束,即清除本地数据源线程变量,使其换回到默认数据源
	@After("@annotation(com.spring.cloud.api.annotation.DS)")
	public void afterSwitchDS(JoinPoint point){

		DynamicDataSource.clearDataSource();

	}
}

8:关闭springboot自带的数据源配置,导入自定义的数据配置(可以不用,这里这是为了提前加载配置类)

import com.joolun.cloud.center.api.config.DataSourceConfig;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Import;

/**
 * @author xz_10086
 * @date 2022/05/11
 * 通用模块
 */
@Import({DataSourceConfig.class}) //可以不用写,这里作用只是提前导入此配置
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class}) //关闭springboot自带的数据源配置
public class ApiApplication {

	public static void main(String[] args) {
		SpringApplication.run(ApiApplication.class, args);
	}
}

9:使用

import com.spring.cloud.api.annotation.DS;
import com.spring.cloud.api.util.DynamicDataSource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created xz_10086
 * 2022/6/17 0017 18:33
 */
@RestController
@RequestMapping("/hello")
public class HelloController {

	@DS("duanguoDS") //不写,则使用默认数据源
	@GetMapping("/test")
	public String test(){
		return DynamicDataSource.getDataSource();
	}

	@GetMapping("/test1")
	public String test1(){
		return DynamicDataSource.getDataSource();
	}
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小贞-10086

世纪的浪漫,最不过——雨落星辰

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值