maven搭建 Spinrgboot + mybais 实现多数据源(SQL server) 2.多数据源配置

本文介绍了如何在SpringBoot项目中使用MyBatis配置多个数据源,包括DataSourceConfig类的设置和动态数据源的实现。通过DataSourceContextHoleder和AOP切面实现数据源的动态切换,达到读写分离的效果。同时提到,尽管能切换数据源,但切换过程可能耗时较长,期待优化方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2.多数据源

2.1  多数据源

 DataSourceConfig 类

  多的不说,上代码,上一篇有关于appliaction.yml   pom.xml  mybatis.xml 等配置文件

   地址:.https://blog.csdn.net/qq_41129021/article/details/83538706



import org.apache.log4j.Logger;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
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 org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

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

/**
 * 多数据源配置类 Created by pure on 2018-10-29.
 * 
 * @author 文浩
 *
 */
@Configuration
public class DataSourceConfig {

	private static final Logger log = Logger.getLogger(DataSourceContextHolder.class);

	// 数据源1
	@Bean(name = "ds1")
	@ConfigurationProperties(prefix = "datasource.ds1") // application.properteis中对应属性的前缀
	public DataSource dataSource1() {
		return DataSourceBuilder.create().build();
	}

	// 数据源2
	@Bean(name = "ds2")
	@ConfigurationProperties(prefix = "datasource.ds2") // application.properteis中对应属性的前缀
	public DataSource dataSource2() {
		return DataSourceBuilder.create().build();
	}

	/**
	 * 动态数据源: 通过AOP在不同数据源之间动态切换
	 * 
	 * @return
	 */
	@Primary
	@Bean(name = "dynamicDataSource")
	public DataSource dynamicDataSource() {
		DynamicDataSource dynamicDataSource = new DynamicDataSource();
		// 默认数据源
		dynamicDataSource.setDefaultTargetDataSource(dataSource1());
		// 配置多数据源
		Map<Object, Object> dsMap = new HashMap<Object, Object>();
		dsMap.put("localhost", dataSource1());
		dsMap.put("mstsc", dataSource2());

		dynamicDataSource.setTargetDataSources(dsMap);
		return dynamicDataSource;
	}

	/**
	 * 配置@Transactional注解事物
	 * 
	 * @return
	 */
	@Bean
	public PlatformTransactionManager transactionManager() {
		return new DataSourceTransactionManager(dynamicDataSource());
	}

}

    这里只配置了两个数据源。可根据实际需求配置更多数据源,只需在yml添加数据库连接属性.
附:  driverClassName、url、userName、password 属性名需对应.否则无法正常注入。会出现Null值情况.

 

 2.2 动态数据源 

DataSourceContextHodedr

   

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

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

首先定义一个ContextHolder, 用于保存当前线程使用的数据源名:


import org.apache.log4j.Logger;

/**
 * Created by pure on 2018-10-29.
 * 
 * @author 文浩
 *
 */
public class DataSourceContextHolder {
	/**
	 * 默认数据源
	 */
	public static final String DEFAULT_JDBC = "localhost";

	private static final Logger log = Logger.getLogger(DataSourceContextHolder.class);

	private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

	// 设置数据源名
	public static void setDB(String dbType) {
		log.info("切换到{" + dbType + "}数据源");
		contextHolder.set(dbType);
	}

	// 获取数据源名
	public static String getDB() {
		return (contextHolder.get());
	}

	// 清除数据源名
	public static void clearDB() {
		log.info("clearDataSource : " + contextHolder.get());
		contextHolder.remove();
	}
}

然后自定义一个javax.sql.DataSource接口的实现,这里只需要继承Spring为我们预先实现好的父类AbstractRoutingDataSource即可:


import org.jboss.logging.Logger;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * Created by pure on 2018-10-29.
 * 
 * @author 文浩
 *
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

	private static final Logger log = Logger.getLogger(DynamicDataSource.class);

	@Override
	protected Object determineCurrentLookupKey() {

		log.info("DynamicDataSource   :" + DataSourceContextHolder.getDB());
		return DataSourceContextHolder.getDB();
	}
}

 自定义注释@JDBC用于在编码时指定方法使用哪个数据源:



import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface JDBC {
	String value() default "datasource1";
}

编写AOP切面,实现切换逻辑:


import org.apache.log4j.Logger;
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;

/**
 * 自定义注解 + AOP的方式实现数据源动态切换。 Created by pure on 2018-10-29.
 * 
 * @author 文浩
 *
 */
@Aspect
@Component
public class DynamicDataSourceAspect {

	private static final Logger log = Logger.getLogger(DynamicDataSourceAspect.class);

	@Before("@annotation(JDBC)")
	public void beforeSwitchDS(JoinPoint point) {
		// 获得当前访问的class
		Class<?> className = point.getTarget().getClass();
		// 获得访问的方法名
		String methodName = point.getSignature().getName();
		// 得到方法的参数的类型
		Class[] argClass = ((MethodSignature) point.getSignature()).getParameterTypes();
		String dataSource = DataSourceContextHolder.DEFAULT_JDBC;
		try {
			// 得到访问的方法对象
			Method method = className.getMethod(methodName, argClass);
			// 判断是否存在@DS注解
			if (method.isAnnotationPresent(JDBC.class)) {
				JDBC annotation = method.getAnnotation(JDBC.class);
				// 取出注解中的数据源名
				dataSource = annotation.value();
				log.info("取出数据源名:" + dataSource);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 切换数据源
		DataSourceContextHolder.setDB(dataSource);
	}

	@After("@annotation(DS)")
	public void afterSwitchDS(JoinPoint point) {
		log.info("clearDataSource   :" + DataSourceContextHolder.getDB());
		DataSourceContextHolder.clearDB();
	}
}

最后:需要关闭spring boot的自动注入。

Application类上添加此注解 @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class }) // 关闭dataSource自动注入

完成之后在service中添加注解指定数据库名就可以啦。

例:

搞定,愉快的切换数据库源吧.  此方法经测试在切换数据源的时候耗时大概有个十来秒左右,目前还不知优化方法,也不知道为什么需要那么久,有知道的小伙伴可以共同交流.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值