spring boot 集成mqtt,动态数据源,时序数据库TDengine (一)

本文章使用 spring boot3、 java21、maven工程

1、pom依赖  

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-3-starter</artifactId>
            <version>1.2.21</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

         <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

         <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.5</version>
        </dependency>
        <!-- tdengine taos驱动 -->
        <dependency>
            <groupId>com.taosdata.jdbc</groupId>
            <artifactId>taos-jdbcdriver</artifactId>
            <version>3.0.0</version>
        </dependency>

   2、yml配置

server:
  port: 31001
  servlet:
    context-path: /dataCapture
spring:
  datasource:
    jsdb:
      driver-class-name: com.taosdata.jdbc.TSDBDriver
      url: jdbc:TAOS://192.168.1.60:6030/data_capture?charset=utf8
      username: root
      password: taosdata
    kbdb:
      driver-class-name: com.taosdata.jdbc.TSDBDriver
      url: jdbc:TAOS://192.168.1.60:6030/data_capture_kb?charset=utf8
      username: root
      password: taosdata
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initial-size: 2
      max-active: 30
      min-idle: 2
      max-wait: 5000
      pool-prepared-statements: true
      validation-query: select 1
      validation-query-timeout: 1
      test-on-borrow: false
      test-on-return: true
      test-while-idle: true
      time-between-eviction-runs-millis: 10000
      min-evictable-idle-time-millis: 30001
      filters: stat
mybatis-plus:
  type-aliases-package: com.hiabr.web
  mapper-locations: classpath:mapper/**/*Mapper.xml
  configuration:
    default-statement-timeout: 120
    map-underscore-to-camel-case: true
    cache-enabled: false
    call-setters-on-nulls: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3、核心配置类

import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.hiabr.web.common.DynamicRoutingDataSource;
import com.hiabr.web.enums.DataSourceKey;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

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

@Configuration
@MapperScan(basePackages = "com.hiabr.web.dao")
public class DynamicDataSourceConfiguration {


    
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.jsdb")
    public DataSource dbMaster() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.kbdb")
    public DataSource dbSlave1() {
        return DruidDataSourceBuilder.create().build();
    }


    @Bean
    public DataSource dynamicDataSource() {
        DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
        dataSource.setDefaultTargetDataSource(dbMaster());
        Map<Object, Object> dataSourceMap = new HashMap<>(4);
        dataSourceMap.put(DataSourceKey.DB_MASTER, dbMaster());
        dataSourceMap.put(DataSourceKey.DB_SLAVE1, dbSlave1());
        dataSource.setTargetDataSources(dataSourceMap);
        return dataSource;
    }

    // 使用yml配置文件中mybatis-plus全局配置
    @Bean
    @ConfigurationProperties(prefix = "mybatis-plus.configuration")
    public MybatisConfiguration mybatisConfiguration() {
        return new MybatisConfiguration();
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource());
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/**/*Mapper.xml"));
        // 设置mybatis-plus全局配置,不配置会出现例如下划线无法转驼峰,日志等
        sqlSessionFactoryBean.setConfiguration(mybatisConfiguration());
        return sqlSessionFactoryBean.getObject();
    }




    @Bean
    public SqlSessionTemplate sqlSessionTemplate() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory());
    }

    /**
     * 事务管理
     *
     * @return 事务管理实例
     */
    @Bean
    public PlatformTransactionManager platformTransactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}

4、DynamicRoutingDataSource 类

import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @description:
 * @author: hanwei
 * @date: 2025/5/7
 */
@Slf4j
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
//        log.info("当前数据源:{}"+ DynamicDataSourceContextHolder.get());
        return DynamicDataSourceContextHolder.get();
    }
}

5、自定义注解、aop切面

import com.hiabr.web.enums.DataSourceKey;

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


    // @Target:注解的作用目标        

  //  @Target(ElementType.TYPE)   //接口、类、枚举、注解
    //   @Target(ElementType.METHOD) // 方法

/**
 * @description:
 * @author: hanwei
 * @date: 2025/5/7
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TargetDataSource {
    DataSourceKey dataSourceKey();
}



public enum DataSourceKey {

    DB_MASTER,
    DB_SLAVE1
}



import com.hiabr.web.annaotation.TargetDataSource;
import com.hiabr.web.enums.DataSourceKey;
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.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;


/**
 * @description:
 * @author: hanwei
 * @date: 2025/5/7
 */
@Aspect
@Order(1)
@Component
@Slf4j
public class DynamicDataSourceAspect {

    
    @Pointcut("execution(* com.hiabr.web.service.*.*(..))")
    public void pointCut() {
    }

    /**
     * 执行方法前更换数据源
     *
     * @param joinPoint        切点
     * @param targetDataSource 动态数据源
     */
    @Before("@annotation(targetDataSource)")
    public void doBefore(JoinPoint joinPoint, TargetDataSource targetDataSource) {
        DataSourceKey dataSourceKey = targetDataSource.dataSourceKey();
        if (dataSourceKey == DataSourceKey.DB_SLAVE1) {
            log.info(String.format("设置数据源为  %s", DataSourceKey.DB_SLAVE1));
            DynamicDataSourceContextHolder.set(DataSourceKey.DB_SLAVE1);
        } else {
            log.info(String.format("使用默认数据源  %s", DataSourceKey.DB_MASTER));
            DynamicDataSourceContextHolder.set(DataSourceKey.DB_MASTER);
        }
    }

    /**
     * 执行方法后清除数据源设置
     *
     * @param joinPoint        切点
     * @param targetDataSource 动态数据源
     */
    @After("@annotation(targetDataSource)")
    public void doAfter(JoinPoint joinPoint, TargetDataSource targetDataSource) {
        log.info(String.format("当前数据源  %s  执行清理方法", targetDataSource.dataSourceKey()));
        DynamicDataSourceContextHolder.clear();
    }

}
6、DynamicDataSourceContextHolder 类
import com.hiabr.web.enums.DataSourceKey;
import org.apache.commons.lang3.RandomUtils;

/**
 * @description:
 * @author: hanwei
 * @date: 2025/5/7
 */
public class DynamicDataSourceContextHolder {
    private static final ThreadLocal<DataSourceKey> currentDatesource = new ThreadLocal<>();

    /**
     * 清除当前数据源
     */
    static void clear() {
        currentDatesource.remove();
    }

    /**
     * 获取当前使用的数据源
     *
     * @return 当前使用数据源的ID
     */
    static DataSourceKey get() {
        return currentDatesource.get();
    }

    /**
     * 设置当前使用的数据源
     *
     * @param value 需要设置的数据源ID
     */
    static void set(DataSourceKey value) {
        currentDatesource.set(value);
    }
}

7、通过注解切换数据源  

@TargetDataSource(dataSourceKey = DataSourceKey.DB_SLAVE1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hanway116

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值