springboot兼容clickhouse数据库多数据源配置(基于mybatis-plus)

  1. pom文件引入相关依赖

    • 
      <!-- 注意版本的兼容性 -->
      <!--  mybatis-plus多数据源-->
              <dependency>
                  <groupId>com.baomidou</groupId>
                  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
                  <version>3.6.1</version>
              </dependency>
      
      • 注意引入mybatis-plus多数据源的maven依赖时,如果与mysql-connector-java的依赖版本不匹配的话会报如下错误:
      Error creating bean with name 'dataSource' defined in class path resource [com/baomidou/dynamic/datasource/spring/boot/autoconfigure/DynamicDataSourceAutoConfiguration.class]: Invocation of init method failed; nested exception is com.baomidou.dynamic.datasource.exception.ErrorCreateDataSourceException: druid create error
      
    • 	<!--        clickhouse的mergeTree引擎默认支持lz4压缩,当使用clickhouse版本支持lz4压缩时需要引入-->
              <dependency>
                  <groupId>org.lz4</groupId>
                  <artifactId>lz4-java</artifactId>
                  <version>1.8.0</version>
              </dependency>
      
      • clickhouse的mergeTree引擎默认支持lz4压缩,当使用clickhouse版本支持lz4压缩时需要引入,否则使用到clickhouse数据源时报以下错误
      LZ4 is not supported. Please disable compression(compress=0), modify the algorithm(e.g. compress_algorithm=gzip), or add the missing libraries to the classpath., server ClickHouseNode [uri=http://59.110.218.73:8123/ets_test]@-1543363112
      
    • <!--        mysql 驱动-->
              <dependency>
                  <groupId>mysql</groupId>
                  <artifactId>mysql-connector-java</artifactId>
                  <version>8.0.29</version>
      <!--            <version>5.1.45</version>-->
              </dependency>
          
          <!-- mybatis-plus -->
              <dependency>
                  <groupId>com.baomidou</groupId>
                  <artifactId>mybatis-plus-boot-starter</artifactId>
                  <version>3.4.1</version>
              </dependency>
      <!--        druid-->
              <dependency>
                  <groupId>com.alibaba</groupId>
                  <artifactId>druid-spring-boot-starter</artifactId>
                  <version>1.1.22</version>
              </dependency>
          
          <!--        clickhouse-->
              <dependency>
                  <groupId>com.clickhouse</groupId>
                  <artifactId>clickhouse-jdbc</artifactId>
                  <version>0.4.6</version>
              </dependency>
      
  2. yml配置

    spring:
      application:
        # 应用名称
        name: more-datasource
      servlet:
        multipart:
          max-file-size: 10MB
          max-request-size: 10MB
      datasource:
        dynamic:
          # 指定默认数据源
          primary: mysql
          # true:找不到数据源报错
          strict: false
          datasource:
            mysql:
              driver-class-name: com.mysql.cj.jdbc.Driver
              url: jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxx?characterEncoding=utf8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true&connectTimeout=4000&socketTimeout=300000&useServerPrepStmts=true&cachePrepStmts=true&serverTimezone=Asia/Shanghai
              username: etsadmin
              password: etsadmin
              type: com.alibaba.druid.pool.DruidDataSource
              druid:
                #初始化时建立物理连接的个数
                initial-size: 5
                #最小连接池数量
                min-idle: 5
                #最大连接池数量
                max-active: 20
                #获取连接时最大等待时间,单位毫秒
                max-wait: 60000
                #申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
                test-while-idle: true
                #既作为检测的间隔时间又作为testWhileIdel执行的依据
                time-between-eviction-runs-millis: 60000
                #销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
                min-evictable-idle-time-millis: 30000
                #用来检测连接是否有效的sql 必须是一个查询语句
                validation-query: select 1
                #申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
                test-on-borrow: false
                #归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
                test-on-return: false
                #是否缓存preparedStatement,mysql5.5+建议开启
                pool-prepared-statements: true
                #当值大于0时poolPreparedStatements会自动修改为true
                max-pool-prepared-statement-per-connection-size: 20
            clickhouse:
              driverClassName: com.clickhouse.jdbc.ClickHouseDriver
              url: jdbc:clickhouse://xxx.xxx.xxx.xxx:8123/xxx
              username: default
              password:
              druid:
                initial-size: 5
                min-idle: 5
                max-active: 20
                max-wait: 60000
                test-while-idle: true
                time-between-eviction-runs-millis: 60000
                min-evictable-idle-time-millis: 30000
                test-on-borrow: false
                test-on-return: false
                pool-prepared-statements: true
                max-pool-prepared-statement-per-connection-size: 20
    
    
    
    mybatis-plus:
    #  mapper-locations: classpath*:com/verification/mapper/xml/*Mapper.xml
      mapper-locations: classpath*:mapper/mysql/*.xml, classpath*:mapper/clickhouse/*.xml
      global-config:
        # 关闭MP3.0自带的banner
        banner: false
        db-config:
          #主键类型
          #      id-type: ASSIGN_ID
          # 默认数据库表下划线命名
          table-underline: true
      configuration:
        # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
        # 返回类型为Map,显示null对应的字段
        call-setters-on-nulls: true
    
  3. 添加多数据源相应注解

    • @Target({ ElementType.TYPE, ElementType.METHOD })
      @Retention(RetentionPolicy.RUNTIME)
      @DS("mysql")
      public @interface MySQL{
      }
      
    • @Target({ ElementType.TYPE, ElementType.METHOD })
      @Retention(RetentionPolicy.RUNTIME)
      @DS("clickhouse")
      public @interface ClickHouse {
      }
      
  4. 多数据源注解的使用

    • 在mapper接口上使用(推荐)

      @MySQL
      public interface MEtsAnalysisReportInfoMapper {
          List<MEtsAnalysisReportInfo> selectListMEtsAnalysisReportInfo();
          void insertMEtsAnalysisReportInfo(MEtsAnalysisReportInfo etsAnalysisReportInfo);
      }
      
      @ClickHouse 
      public interface CTOrderMtMapper {
          List<CTOrderMt> selectListCTOrderMt();
      
          void insertCTOrderMt(CTOrderMt ctOrderMt);
      }
      
    • 在service类上或方法中使用(不推荐),由于方法中可能会涉及到两个数据源,这时会报其中有个数据源的表找不到

      	@MySQL
          @DSTransactional
          @Override
          public void insertMEtsAnalysisReportInfo() {
      
             mEtsAnalysisReportInfoMapper.insertMEtsAnalysisReportInfo(MEtsAnalysisReportInfo.builder()
                      .reportSettingId("test")
                      .content("test")
                      .userId("test")
                      .createTime(new Date())
                      .updateTime(new Date())
                      .build());
              ctOrderMtMapper.insertCTOrderMt(CTOrderMt.builder()
                      .id(Integer.valueOf("111111"))
                      .skuId("test")
                      .totalAmount(new BigDecimal("1111.111"))
                      .createTime(new Date()).build());
      //        int a = 1/0;
          }
      
  5. 多数据源事务(单体应用)

    • 如果sevice方法中涉及到单一数据源的话,可以使用Transactional遇到异常能够正常回滚

      @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
          @Override
          public void insertMEtsPubRole() {
      
              mePubRoleMapper.insertMEtsPubRole(MEtsPubRole.builder()
                                                           .code("test")
                                                           .name("test")
                                                           .build());
              // 单一数据源能够正常回滚
              //        int a = 1/0;
      
          }
      
    • 如果service方法中涉及到两个数据源的话,需要使用@DSTransactional,才能使MySQL的事务生效,如果使用Transactional则会报其中一个数据源找不到表

          @DSTransactional
          @Override
          public void insertMEtsAnalysisReportInfo() {
      
             mEtsAnalysisReportInfoMapper.insertMEtsAnalysisReportInfo(MEtsAnalysisReportInfo.builder()
                      .reportSettingId("test")
                      .content("test")
                      .userId("test")
                      .createTime(new Date())
                      .updateTime(new Date())
                      .build());
              ctOrderMtMapper.insertCTOrderMt(CTOrderMt.builder()
                      .id(Integer.valueOf("111111"))
                      .skuId("test")
                      .totalAmount(new BigDecimal("1111.111"))
                      .createTime(new Date()).build());
              int a = 1/0;
          }
      
    • clickhouse是不支持事务的,无论是否使用事务,对clickhouse都不生效

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐