git文件地址:项目首页 - SpringBoot连接TDengine和MySQL双数据源:SpringBoot连接TDengine和MySQL双数据源 - GitCode
1、yml配置
spring:
datasource:
druid:
mysql:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
tdengine:
driver-class-name: com.taosdata.jdbc.rs.RestfulDriver
url: jdbc:TAOS-RS://localhost:6041/test?&timezone=UTC-8&charset=UTF-8&locale=en_US.UTF-8
username: root
password: 1234
type: com.alibaba.druid.pool.DruidDataSource
2、pom依赖
org.springframework.boot
spring-boot-starter-jdbc
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-web-services
org.springframework.boot
spring-boot-devtools
runtime
true
mysql
mysql-connector-java
8.0.33
runtime
com.alibaba
druid-spring-boot-starter
1.2.15
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.apache.commons
commons-lang3
3.7
com.baomidou
mybatis-plus-boot-starter
3.4.3
com.baomidou
mybatis-plus
3.5.3.1
com.baomidou
mybatis-plus-extension
3.5.3.1
com.baomidou
mybatis-plus-generator
3.5.3.1
com.baomidou
dynamic-datasource-spring-boot-starter
3.5.1
com.google.guava
guava
32.1.3-jre
io.swagger
swagger-annotations
1.6.3
com.taosdata.jdbc
taos-jdbcdriver
3.2.7
cn.hutool
hutool-all
5.3.8
3、重写SqlSession
package com.example.testtdengine.config.db;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.session.*;
import org.mybatis.spring.MyBatisExceptionTranslator;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.util.Assert;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import static java.lang.reflect.Proxy.newProxyInstance;
import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable;
import static org.mybatis.spring.SqlSessionUtils.*;
public class CustomSqlSessionTemplate extends SqlSessionTemplate {
private final SqlSessionFactory sqlSessionFactory;
private final ExecutorType executorType;
private final SqlSession sqlSessionProxy;
private final PersistenceExceptionTranslator exceptionTranslator;
private Map
4、设置切面
@Component
@Order(value = -100)
@Slf4j
@Aspect
public class DataSourceSwitchAspect {
@Pointcut("execution(* com.example.testtdengine.mapper.mysql..*.*(..))")
private void mysqlAspect() {
}
@Pointcut("execution(* com.example.testtdengine.mapper.tdengine..*.*(..))")
private void tdengineAspect() {
}
@Before("mysqlAspect()")
public void mysql() {
log.info("切换到mysql 数据源...");
DbContextHolder.setDbType(DBTypeEnum.mysql);
}
@Before("tdengineAspect()")
public void tdengine() {
log.info("切换到tdengine 数据源...");
DbContextHolder.setDbType(DBTypeEnum.tdengine);
}
@After("mysqlAspect()")
public void clear1() {
log.info("清除mysql数据源...");
DbContextHolder.clearDbType();
}
@After("tdengineAspect()")
public void clear2() {
log.info("清除tdengine数据源...");
DbContextHolder.clearDbType();
}
}
5、DBContextHolder使用ThreadLocal将数据源连接存储在当前线程的threadlocals(ThreadLocalMap)中,在连接数据库时自动获取当前线程对于的数据源
package com.example.testtdengine.config.db;
public class DbContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal<>();
/**
* 设置数据源
*
* @param dbTypeEnum
*/
public static void setDbType(DBTypeEnum dbTypeEnum) {
contextHolder.set(dbTypeEnum.getValue());
}
/**
* 取得当前数据源
*
* @return
*/
public static String getDbType() {
return (String) contextHolder.get();
}
/**
* 清除上下文数据
*/
public static void clearDbType() {
contextHolder.remove();
}
}
6、数据库枚举
package com.example.testtdengine.config.db;
public enum DBTypeEnum {
mysql("mysql"),
tdengine("tdengine");
private String value;
DBTypeEnum(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
7、封装动态切库
package com.example.testtdengine.config.db;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
}
8、修改mybatis全局配置
package com.example.testtdengine.config.db;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
public class MyGlobalConfig extends GlobalConfig {
@Autowired
private CustomSqlSessionTemplate sqlSessionTemplate;
private static CustomSqlSessionTemplate customSqlSessionTemplate;
@Override
public SqlSessionFactory getSqlSessionFactory() {
return customSqlSessionTemplate.getSqlSessionFactory();
}
@PostConstruct
public void init() {
MyGlobalConfig.customSqlSessionTemplate = sqlSessionTemplate;
}
}
9、注入分页插件
package com.example.testtdengine.config;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.example.testtdengine.config.db.DBTypeEnum;
import com.example.testtdengine.config.db.DynamicDataSource;
import com.example.testtdengine.config.interceptor.TaosDynamicTableNameInnerInterceptor;
import com.example.testtdengine.config.interceptor.TaosTableNameHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.springframework.beans.factory.annotation.Qualifier;
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.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 动态表名插件
TaosDynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new TaosDynamicTableNameInnerInterceptor();
dynamicTableNameInnerInterceptor.setTableNameHandler(new TaosTableNameHandler());
interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
return interceptor;
}
@Bean(name = "mysql")
@ConfigurationProperties(prefix = "spring.datasource.druid.mysql")
public DataSource mysql() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "tdengine")
@ConfigurationProperties(prefix = "spring.datasource.druid.tdengine")
public DataSource tdengine() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DataSource multipleDataSource(@Qualifier("mysql") DataSource mysql,
@Qualifier("tdengine") DataSource tdengine) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map targetDataSources = new HashMap<>();
targetDataSources.put(DBTypeEnum.mysql.getValue(), mysql);
targetDataSources.put(DBTypeEnum.tdengine.getValue(), tdengine);
// 程序默认数据源,这个要根据程序调用数据源频次,经常把常调用的数据源作为默认
dynamicDataSource.setDefaultTargetDataSource(tdengine);
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
@Bean("sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(multipleDataSource(mysql(), tdengine()));
MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);
configuration.setCallSettersOnNulls(true);
configuration.setCacheEnabled(false);
GlobalConfig.DbConfig dab = new GlobalConfig.DbConfig();
dab.setIdType(IdType.AUTO);
sqlSessionFactory.setConfiguration(configuration);
//添加分页功能
sqlSessionFactory.setPlugins(new Interceptor[]{
mybatisPlusInterceptor()
});
return sqlSessionFactory.getObject();
}
}
主要配置如下图所示