Spring boot+MYSQL多数据源

引入maven:

com.alibaba

druid

1.1.22

DataBase :
package com.example.zhwj.config;

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 DataBase {

String value() default "db1";

}

DatabaseContextHolder :
package com.example.zhwj.config;

public class DatabaseContextHolder {

private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
//默认数据源
public static final String DEFAULT_DS = "db1";

public static void setDatabaseType(String type) {
	contextHolder.set(type);
}

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

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

}

DataSourceAspect :
package com.example.zhwj.config;

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.core.Ordered;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class DataSourceAspect implements Ordered {

@Pointcut("@annotation(DataBase)")//注意:这里的xxxx代表的是上面public @interface DataSource这个注解DataSource的包名
public void dataSourcePointCut() {

}

@SuppressWarnings("rawtypes")
@Before("dataSourcePointCut()")
public void beforeSwitchDS(JoinPoint point){
	//获得当前访问的class
	Class<?> className = point.getTarget().getClass();
	//获得访问的方法名
	String methodName = point.getSignature().getName();
	//得到方法的参数的类型
	Class[] argClass = ((MethodSignature)point.getSignature()).getParameterTypes();

	String dataSource = DatabaseContextHolder.DEFAULT_DS;
	try {
		// 得到访问的方法对象
		Method method = className.getMethod(methodName, argClass);

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


@After("dataSourcePointCut()")
public void afterSwitchDS(JoinPoint point){
	DatabaseContextHolder.clearDataSource();
}


@Override
public int getOrder() {
	return 1;
}

}

DruidConfig:
package com.example.zhwj.config;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.google.common.collect.Lists;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

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

@Configuration
public class DruidConfig {

@Autowired
private Environment env;

@Primary
@ConfigurationProperties(prefix="spring.datasource.db1")
@Bean(name = "datasource1")
public DataSource dataSourceDB1(Filter statFilter) throws SQLException{
	DruidDataSource dataSource = new DruidDataSource();
	dataSource.setProxyFilters(Lists.newArrayList(statFilter()));
	return dataSource;
}

/**
 * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@autowire注解报错
 * @Qualifier 根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入(例如有多个DataSource类型的实例)
 */
@Bean(name = "dynamicDataSource")
public DynamicDataSource dataSource(@Qualifier("datasource1") DataSource datasource1) {
	Map<Object, Object> targetDataSources = new HashMap<>();
	targetDataSources.put(DatabaseContextHolder.DEFAULT_DS, datasource1);
	DynamicDataSource dataSource = new DynamicDataSource();
	dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
	dataSource.setDefaultTargetDataSource(datasource1);// 默认的datasource设置为dataSourceDB1

	return dataSource;
}


/**
 * 根据数据源创建SqlSessionFactory
 */
@Bean
public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception {
	SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
	fb.setDataSource(ds);// 指定数据源(这个必须有,否则报错)
	// 下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加
	fb.setTypeAliasesPackage("com.example.zhwj.model");// 指定基包
	fb.setMapperLocations(
	        new PathMatchingResourcePatternResolver().getResources("mapper/*.xml"));//
	return fb.getObject();
}

/**
 * 配置事务管理器
 */
@Bean
public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
	return new DataSourceTransactionManager(dataSource);
}

@Bean
public Filter statFilter(){
	StatFilter filter = new StatFilter();
	filter.setSlowSqlMillis(5000);
	filter.setLogSlowSql(true);
	filter.setMergeSql(true);
	return filter;
}


@Bean
public ServletRegistrationBean servletRegistrationBean(){
	//org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册.
	ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");

	//添加初始化参数:initParams
	//白名单:
	// servletRegistrationBean.addInitParameter("allow","127.0.0.1");
	//IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
	//servletRegistrationBean.addInitParameter("deny","192.168.1.73");
	//登录查看信息的账号密码.
	servletRegistrationBean.addInitParameter("loginUsername","admin");
	servletRegistrationBean.addInitParameter("loginPassword","123456");
	//在日志中打印执行慢的sql语句
	servletRegistrationBean.addInitParameter("logSlowSql", "true");
	//是否能够重置数据.
	servletRegistrationBean.addInitParameter("resetEnable","false");

	return servletRegistrationBean;
}


@Bean
public FilterRegistrationBean druidStatFilter(){

	FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
	filterRegistrationBean.setFilter(new WebStatFilter());
	filterRegistrationBean.addUrlPatterns("/*");
	//过滤文件类型
	filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
	//监控单个url调用的sql列表
	filterRegistrationBean.addInitParameter("profileEnable", "true");
	return filterRegistrationBean;
}

}

DynamicDataSource :
package com.example.zhwj.config;

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

public class DynamicDataSource extends AbstractRoutingDataSource {

/**
 * 动态数据源(需要继承AbstractRoutingDataSource)
 */
@Override
protected Object determineCurrentLookupKey() {
	return DatabaseContextHolder.getDatabaseType();
}

}

spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
db1:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&useTimezone=true&serverTimezone=Asia/Shanghai
username: root
password: 123456

以上配置完成后,即可在你的serviceImpl中加入注解
@DataBase(value = "db1")
即可使用

原文地址:https://www.cnblogs.com/zzqcupidzhq/p/13969360.html