1·nacos数据源配置
spring.datasource.druid.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.db1.url=jdbc:mysql://192.168.0.111:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true
spring.datasource.druid.db1.username=root
spring.datasource.druid.db1.password=root
spring.datasource.druid.db2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.db2.url=jdbc:mysql://192.168.0.112:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowMultiQueries=true
spring.datasource.druid.db2.username=root
spring.datasource.druid.db2.password=root
mybatis-plus.mapper-locations=classpath:**/*/dao/**/*Mapper.xml
2、创建配置类MyBatiesPlusConfiguration
package com.chenvacloud.information.config.db.multiple;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
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.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@Configuration
public class MyBatiesPlusConfiguration {
/**
* SQL执行效率插件
*/
@Bean(name = "db1")
@ConfigurationProperties(prefix = "spring.datasource.druid.db1")
public DataSource db1() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "db2")
@ConfigurationProperties(prefix = "spring.datasource.druid.db2")
public DataSource db2() {
return DruidDataSourceBuilder.create().build();
}
/**
* 动态数据源配置
*
* @return
*/
@Bean
@Primary
public DataSource multipleDataSource(
@Qualifier("db1") DataSource db1,
@Qualifier("db2") DataSource db2) {
MultipleDataSource multipleDataSource = new MultipleDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceEnum.DB1.getValue(), db1);
targetDataSources.put(DataSourceEnum.DB2.getValue(), db2);
Set<Object> keySet = targetDataSources.keySet();
for (Object obj : keySet) {
DataSourceContextHolder.dataSourceIds.add(obj.toString());
}
//添加数据源
multipleDataSource.setTargetDataSources(targetDataSources);
//设置默认数据源
multipleDataSource.setDefaultTargetDataSource(db1);
return multipleDataSource;
}
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Value("${mybatis-plus.mapper-locations}") String[] mybatisPlusLocations) throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(multipleDataSource(db1(), db2()));
ResourcePatternResolver loader = new PathMatchingResourcePatternResolver();
Resource[] root = {};
for (String mapperLocation : mybatisPlusLocations) {
int len = root.length;
Resource[] resource = loader.getResources(mapperLocation);
root = Arrays.copyOf(root, root.length + resource.length);
System.arraycopy(resource, 0, root, len, resource.length);
}
sqlSessionFactoryBean.setMapperLocations(root);
// 打jar包部署时无效, 原因未知
// sqlSessionFactoryBean.setTypeAliasesPackage("org.admin.erp.*.entity");
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCacheEnabled(false);
sqlSessionFactoryBean.setConfiguration(configuration);
return sqlSessionFactoryBean.getObject();
}
/*@Bean
public GlobalConfiguration globalConfiguration() {
GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector());
conf.setLogicDeleteValue("-1");
conf.setLogicNotDeleteValue("1");
conf.setIdType(0);
//conf.setMetaObjectHandler(new MyMetaObjectHandler());
conf.setDbColumnUnderline(true);
conf.setRefresh(true);
return conf;
}*/
}
3、自定义MultipleDataSource
package com.chenvacloud.information.config.db.multiple;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class MultipleDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
4、操作数据源类DataSourceContextHolder
package com.chenvacloud.information.config.db.multiple;
import java.util.ArrayList;
import java.util.List;
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new InheritableThreadLocal<>();
// 存放数据源id
public static List<String> dataSourceIds = new ArrayList<>();
/**
* 设置数据源
*
* @param db
*/
public static void setDataSource(String db) {
contextHolder.set(db);
}
/**
* 取得当前数据源
*
* @return
*/
public static String getDataSource() {
return contextHolder.get();
}
/**
* 清除上下文数据
*/
public static void clear() {
contextHolder.remove();
}
/** 判断当前数据源是否存在
*
* @param dataSourceId
* @return
*/
public static boolean isContainsDataSource(String dataSourceId) {
return dataSourceIds.contains(dataSourceId);
}
}
5、配置自定义注解TargetDataSource
package com.chenvacloud.information.config.db.multiple;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
DataSourceEnum value() default DataSourceEnum.DB1;
}
6、配置数据源枚举DataSourceEnum
package com.chenvacloud.information.config.db.multiple;
/**
* 列出所有的数据源key(常用数据库名称来命名)
* 注意:
* 1)这里数据源与数据库是一对一的
* 2)DatabaseType中的变量名称就是数据库的名称
*/
public enum DataSourceEnum {
DB1("db1"), DB2("db2");
private String value;
DataSourceEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
7、AOP切换数据源AopCompreConfig
package com.chenvacloud.information.aop;
import com.chenvacloud.information.config.db.multiple.DataSourceContextHolder;
import com.chenvacloud.information.config.db.multiple.TargetDataSource;
import lombok.extern.slf4j.Slf4j;
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.springframework.context.annotation.Scope;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Scope("prototype")
@Component
public class AopCompreConfig {
/**
* 前置通知:执行方法指定数据源
*
* @param targetDataSource
* @throws Throwable
*/
@Order(-1)
@Before("@annotation(targetDataSource)")
public void doBefore(JoinPoint joinPoint, TargetDataSource targetDataSource) {
String dbid = targetDataSource.value().getValue();
if (!DataSourceContextHolder.isContainsDataSource(dbid)) {
log.error("数据源 " + dbid + " 不存在, 使用默认的数据源 -> " + joinPoint.getSignature());
} else {
log.debug("使用数据源:" + dbid);
DataSourceContextHolder.setDataSource(dbid);
}
}
/**
* 后置通知:移除数据源
*
* @param targetDataSource
* @throws Throwable
*/
@Order(-1)
@After("@annotation(targetDataSource)")
public void doAfter(TargetDataSource targetDataSource) {
log.info("移除数据源---" + targetDataSource.value().getValue());
DataSourceContextHolder.clear();
}
}
结束