multipleDataSource学习
在一些特定的场景下需要向多个数据库进行操作.如:一些查询统计,一些有主从数据库项目等.这项项目中我们就需要一个可操作多个数据源框架.
- 项目时序图
- 各个类作用
- pom.xml maven配置文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.guanheng</groupId>
<artifactId>MoreDataSource</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<spring.boot.version>2.0.3.RELEASE</spring.boot.version>
<spring.mybatis.version>1.3.2</spring.mybatis.version>
<myslq.connect.version>8.0.11</myslq.connect.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>hikari-cp</groupId>
<artifactId>hikari-cp</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${spring.mybatis.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring.boot.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${spring.mybatis.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${myslq.connect.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
- application.yml Springboot配置文件和多数据源的配置
datasources:
- name: transformer
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/transformers?useUnicode=true&characterEncoding=UTF8&autoReconnect=true&useSSL=false
username: admin
password: ****
- DataSources.java 读取配置信息
@Data
@ConfigurationProperties()
public class DataSources {
private List<DataSourceProperties> datasources;
}
- DataSource.java 自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
DataSourceType value();
}
- DataSourceAspect.java 切面操作
@Aspect
@Component
public class DataSourceAspect {
private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>();
static DataSourceType getDatabaseType() {
return contextHolder.get();
}
@Before("execution(public * com.guanheng..*Dao.*(..))")
public void setDataSourceKey(JoinPoint point) {
Object dao = point.getTarget();
DataSource dataSource = dao.getClass().getDeclaredAnnotation(DataSource.class);
if(dataSource != null){
contextHolder.set(dataSource.value());
}else{
throw new IllegalStateException(dao.getClass().getName() + "没有指定 datasource");
}
}
}
- DataSourceConfiguration.java DataSourceBuilder
@Configuration
@EnableConfigurationProperties({DataSources.class})
public class DataSourceConfiguration {
@SuppressWarnings("unchecked")
private <T> T createDataSource(DataSourceProperties properties, Class<? extends DataSource> type) {
return (T) properties.initializeDataSourceBuilder().type(type).build();
}
@Bean
public MultipleDataSource dataSource(DataSources dataSources) {
Map<Object, Object> targetDataSources = new HashMap<>();
dataSources.getDatasources().forEach(properties ->
targetDataSources.put(DataSourceType.from(properties.getName()), createDataSource(properties, HikariDataSource.class))
);
MultipleDataSource dataSource = new MultipleDataSource();
dataSource.setTargetDataSources(targetDataSources);
return dataSource;
}
}
- DataSourceType.java 数据库枚举
public enum DataSourceType {
TRANSFORMER;
public static DataSourceType from (String name) {
for(DataSourceType type : DataSourceType.values()){
if(type.name().equalsIgnoreCase(name)){
return type;
}
}
throw new IllegalArgumentException("Can't get DataSourceType from name " + name);
}
}
- MultipleDataSource.java 继承AbstractRoutingDataSource set TargetDataSources 和 获取dataSource
public class MultipleDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceAspect.getDatabaseType();
}
}
- MyBatisDao.java 基础dao
@SuppressWarnings("all")
@Slf4j
public abstract class MyBatisDao<T, Id> {
protected static final String FIND_BY_ID = "findById";
@Autowired
protected SqlSessionTemplate sqlSession;
private final String nameSpace;
private final Class<T> clazz;
public MyBatisDao() {
if (getClass().getGenericSuperclass() instanceof ParameterizedType) {
clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
} else {
//解决cglib实现aop时转换异常
clazz = (Class<T>) ((ParameterizedType) getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()[0];
// clazz = (Class<T>) getClass().getGenericSuperclass();
}
nameSpace = clazz.getSimpleName();
}
public T findById(Id id) {
return sqlSession.selectOne(sqlId(FIND_BY_ID), id);
}
}
- AdminDao.java
@Repository
@DataSource(DataSourceType.TRANSFORMER)
public class AdminDao extends MyBatisDao<Admin, String> {
}
源码地址:点击下载