ShardingSphere-JDBC-若依框架集成(SpringBoot)
作者:mmseoamin日期:2024-01-19

前言

ShardingSphere基础知识、ShardingSphere-JDBC如何集成进若依框架中

使用的是若依框架(SpringBoot)前后端版本、动态数据源,可自行切换,默认数据源为达梦8

文章目录

    • 前言
    • 基础知识
      • 简介
      • 产品功能
      • 使用
        • 方案一
        • 方案二
        • 方案三
        • 注意点
          • 参考内容

            基础知识

            官网文档地址:https://shardingsphere.apache.org/document/current/cn/overview/

            简介

            1. 开源的分布式数据库中间件解决方案组成的生态圈
            2. 关系型数据库中间件
            3. 产品组件
              • ShardingSphere-JDBC:轻量级Java框架,在Java的JDBC层提供额外服务
              • ShardingSphere-Proxy:透明化的数据库代理端,通过实现数据库二进制协议,对异构语言提供支持

            产品功能

            1. 数据分片:分库、分表(垂直、水平)
            2. 分布式事务
            3. 读写分离
            4. 数据迁移
            5. 联邦查询:跨数据源查询
            6. 数据加密
            7. 影子库:压测数据隔离的影子数据库

            使用

            项目框架:若依前后端分离版本(SpringBoot 2.7.10)

            ORM:Mybatis Plus(mybatis-plus-boot-starter 3.5.3)

            数据库连接池:druid(druid-spring-boot-starter 1.2.15)

            组件:ShardingSphere-JDBC(shardingsphere-jdbc-core-spring-boot-starter 5.2.0)

            方案一

            1. 总pom引入shardingsphere-jdbc-core-spring-boot-starter

              
              
              	org.apache.shardingsphere
                  shardingsphere-jdbc-core-spring-boot-starter
                  5.2.0
              
              
            2. framework模块引入shardingsphere-jdbc-core-spring-boot-starter

            3. admin模块新增配置文件application-shardingsphere.yml

              # 数据源配置
              spring:
                shardingsphere:
                  # 单机模式
                  mode:
                    type: Standalone
                  props:
                    sql-show: true
                  # 数据源配置
                  datasource:
                    names: druid,sharding
                    # 主库数据源
                    master:
                      type: com.alibaba.druid.pool.DruidDataSource
                      driver-class-name: dm.jdbc.driver.DmDriver
                      url: jdbc:dm://localhost:5236?SCHEMA=xx&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&rewriteBatchedStatements=true
                      username: SYSDBA
                      password: SYSDBA
              	  # 分库数据源	
                    sharding:
                      type: com.alibaba.druid.pool.DruidDataSource
                      driver-class-name: dm.jdbc.driver.DmDriver
                      url: jdbc:dm://localhost:5236?SCHEMA=xx
                      username: SYSDBA
                      password: SYSDBA
              #        driver-class-name: com.mysql.jdbc.Driver
              #        url: jdbc:mysql://localhost:3306/ry-order1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
              #        username: root
              #        password: root		
                  # 标准分片配置
                  rules:
                    # 分片规则
                    sharding:
                      tables:
              		  # 表名
                        tb_user:
                          actual-data-nodes: sharding.tb_user_${0..1} # 相当于tb_user_0、tb_user_1
                          table-strategy: # 分表策略
                            standard: # 标准分表策略
                              sharding-column: id                        # 分表列名
                              sharding-algorithm-name: tb_user_inline    # 分表算法名字
              		# 分片算法
                      shardingAlgorithms:
                        tb_user_inline:
              			# 策略类型
                          type: INLINE
                          props:
                            algorithm-expression: tb_user_$->{id % 2} # 结果为0和1,与上面的表名对应
              
            4. 相应修改DruidProperties.java里的配置值

            结果:没有数据分片的效果

            方案二

            在方案一的基础上

            1. DataSourceType加上类型SHARDING

            2. DruidConfig加上数据源

              setDataSource(targetDataSources, DataSourceType.SHARDING.name(), "shardingSphereDataSource");
              
            3. 调用方法上增加数据源类型

              @Override
              @DataSource(DataSourceType.SHARDING)
              public Long insertNew(User user) {
                  return (long) userMapper.insert(user);
              }
              

            注意点:shardingSphereDataSource默认使用的数据源名称就是sharding

            结果:可以进行数据分片

            方案三

            1. 总pom引入shardingsphere-jdbc-core-spring-boot-starter

              
              
              	org.apache.shardingsphere
                  shardingsphere-jdbc-core-spring-boot-starter
                  5.2.0
              
              
            2. framework模块引入shardingsphere-jdbc-core-spring-boot-starter

            3. admin模块配置文件新增配置项指定sharding配置

              spring:
              	shardingsphere:
              		configLocation: application-sharding.yml
              
            4. 新增sharding配置文件application-sharding.yml,注意部分单词驼峰

              # 数据源
              dataSources:
                sharding:
                  dataSourceClassName: com.alibaba.druid.pool.DruidDataSource
                  driverClassName: dm.jdbc.driver.DmDriver
                  url: jdbc:dm://localhost:5236?SCHEMA=xx
                  username: SYSDBA
                  password: SYSDBA
                  maxTotal: 100
              #  ds_1:
              #    dataSourceClassName: com.alibaba.druid.pool.DruidDataSource
              #    driverClassName: com.mysql.cj.jdbc.Driver
              #    url: jdbc:mysql://localhost:3306/ry-order2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
              #    username: root
              #    password: root
              #    maxTotal: 100
              rules:
                - !TRANSACTION
                  defaultType: LOCAL
                - !SHARDING
                  tables:
                    # 表名
                    tb_user:
                      actualDataNodes: sharding.tb_user_$->{0..1}
                      tableStrategy: # 分表策略
                        standard: # 标准分表策略
                          sharding-column: id                        # 分表列名
                          sharding-algorithm-name: tb_user_inline    # 分表算法名字
                  # 分片算法
                  shardingAlgorithms:
                    tb_user_inline:
              		# 策略类型
                      type: INLINE
                        props:
                        algorithm-expression: tb_user_$->{id % 2}
              	
              	# 分布式序列算法配置(主键生成)
                  keyGenerators:
                    # 雪花算法
                    snowflake:
                      type: SNOWFLAKE
              props:
                # 输出SQL
                sql-show: true
              
            5. 新增sharding配置类:ShardingProperties.java

              import org.springframework.beans.factory.annotation.Value;
              import org.springframework.context.annotation.Configuration;
              @Configuration
              public class ShardingProperties {
                  @Value("${spring.shardingsphere.configLocation}")
                  private String configLocation;
                  public String getConfigLocation() {
                      return configLocation;
                  }
              }
              
            6. DataSourceType加上类型SHARDING

            7. DruidConfig加上数据源

              @Bean
              public DataSource shardingDataSource(ShardingProperties shardingProperties) throws Exception
                  {
                      ClassPathResource classPathResource = new ClassPathResource(shardingProperties.getConfigLocation());
                      InputStream inputStream = classPathResource.getInputStream();
                      File tmpFile = File.createTempFile(shardingProperties.getConfigLocation(), ".tmp");
                      Files.copy(inputStream, tmpFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                      DataSource dataSource = YamlShardingSphereDataSourceFactory.createDataSource(tmpFile);
                      return dataSource;
                  }
              // 动态数据源方法加上sharding
              @Bean(name = "dynamicDataSource")
              @Primary
              public DynamicDataSource dataSource(DataSource masterDataSource) {
                      Map targetDataSources = new HashMap<>();
                      targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
                      setDataSource(targetDataSources, DataSourceType.SHARDING.name(), "shardingDataSource");
                      return new DynamicDataSource(masterDataSource, targetDataSources);
                  }
              
            8. 调用方法上增加数据源类型

            结果:可以进行数据分片

            注意点

            1. ShardingSphere各个版本有差异,并且不一定完全向前兼容,与其他框架如Springboot、druid上可能也存在某些版本无法兼容,所以需要注意引入的各个框架的版本

            2. 只有使用分片键进行操作才会通过分表扫描,否则依然是全表扫描

            3. 不支持分片表和单表关联查询

              1. 解决方案:重写sql,不走分片查询
            4. 分页:如果是一些非主流的数据库,不在支持的数据库类型里,则需要适配

              1. 解决方案一:使用支持的数据库方言类型,如MySQL

              2. 解决方案二:通过自定义分页SQL实现

                SELECT * 
                  FROM ( SELECT TMP.*, 
                               ROWNUM ROW_ID 
                          FROM ( SELECT id, 
                                       company_code, 
                                  
                                  FROM table_name ) TMP 
                         WHERE ROWNUM <=?) 
                 WHERE ROW_ID > ?   
                
            5. 无法更新:IService.updateById()

              1. 不能更新分片键字段,因为可能存在更新完不在此分片表里
              2. 实体表字段加注解不更新:@TableField(updateStrategy = FieldStrategy.NEVER)
            6. 表约束失效:唯一性约束在多个表失效

            7. 使用in条件,即使使用分片键,还是会走全路由

            参考内容

            1. 自定义分片算法:参考1、参考2、参考3