• ruoyi框架中添加sharding sphere5.0.0分表(通过spi添加自定义分表策略)


    sharding shphere作为一个分库分表组件,在处理分表业务时,比起自己实现分表功能,还是有很多明显优势的。

    对于一个从0开始的springboot项目,添加sharding sphere分库分表是比较简单的,有时需要在已有的程序框架中添加sharding sphere的分库分表功能,这就需要根据框架本身的特点进行特定的配置了。

    1. 添加依赖

    ruoyi-framework\pom.xml模块添加sharding-jdbc整合依赖:

    1. <!-- sharding-jdbc分库分表 -->
    2. <dependency>
    3. <groupId>org.apache.shardingsphere</groupId>
    4. <artifactId>shardingsphere-jdbc-core</artifactId>
    5. <version>5.0.0</version>
    6. </dependency>

    2. 创建测试库

    这里使用和主程序相同的数据库,所以不需要单独的创建数据库。

    3. 创建两个测试订单表

    1. create table sys_order
    2. (
    3. order_id bigint(20) not null comment '订单ID',
    4. user_id bigint(64) not null comment '用户编号',
    5. status char(1) not null comment '状态(0交易成功 1交易失败)',
    6. order_no varchar(64) default null comment '订单流水',
    7. primary key (order_id)
    8. ) engine=innodb comment = '订单信息表';
    9. create table sys_order_0
    10. (
    11. order_id bigint(20) not null comment '订单ID',
    12. user_id bigint(64) not null comment '用户编号',
    13. status char(1) not null comment '状态(0交易成功 1交易失败)',
    14. order_no varchar(64) default null comment '订单流水',
    15. primary key (order_id)
    16. ) engine=innodb comment = '订单信息表';
    17. create table sys_order_1
    18. (
    19. order_id bigint(20) not null comment '订单ID',
    20. user_id bigint(64) not null comment '用户编号',
    21. status char(1) not null comment '状态(0交易成功 1交易失败)',
    22. order_no varchar(64) default null comment '订单流水',
    23. primary key (order_id)
    24. ) engine=innodb comment = '订单信息表';

    4. 配置文件添加数据源

    application-druid.yml添加测试数据源,位置和主数据源同级位置:

    1. # 数据源配置
    2. spring:
    3. datasource:
    4. type: com.alibaba.druid.pool.DruidDataSource
    5. driverClassName: com.mysql.cj.jdbc.Driver
    6. druid:
    7. # 主库数据源
    8. master:
    9. url: jdbc:mysql://localhost:3306/ry473?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    10. username: root
    11. password: password
    12. # 订单库1
    13. shardsource:
    14. enabled: true
    15. url: jdbc:mysql://localhost:3306/ry473?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    16. username: root
    17. password: password

    5. 代码生成工具生成代码组件

    通过代码生成功能生成sys_order相关组件并添加到项目中,包括页面、控制器、服务层、mapper以及mapper.xml文件等。

    6. 添加shardingsphere配置类

    1. package com.ruoyi.framework.config;
    2. import java.sql.SQLException;
    3. import java.util.Collections;
    4. import java.util.HashMap;
    5. import java.util.Map;
    6. import java.util.Properties;
    7. import javax.sql.DataSource;
    8. import org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory;
    9. import org.apache.shardingsphere.infra.config.algorithm.ShardingSphereAlgorithmConfiguration;
    10. import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
    11. import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
    12. import org.apache.shardingsphere.sharding.api.config.strategy.keygen.KeyGenerateStrategyConfiguration;
    13. import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
    14. import org.springframework.beans.factory.annotation.Qualifier;
    15. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    16. import org.springframework.boot.context.properties.ConfigurationProperties;
    17. import org.springframework.context.annotation.Bean;
    18. import org.springframework.context.annotation.Configuration;
    19. import com.alibaba.druid.pool.DruidDataSource;
    20. import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
    21. import com.ruoyi.framework.config.properties.DruidProperties;
    22. /**
    23. * sharding 配置信息
    24. *
    25. * @author ruoyi
    26. */
    27. @Configuration
    28. public class ShardingDataSourceConfig
    29. {
    30. @Bean
    31. @ConfigurationProperties("spring.datasource.druid.shardsource")
    32. @ConditionalOnProperty(prefix = "spring.datasource.druid.shardsource", name = "enabled", havingValue = "true")
    33. public DataSource shardDataSource(DruidProperties druidProperties)
    34. {
    35. DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
    36. return druidProperties.dataSource(dataSource);
    37. }
    38. // @Bean
    39. // @ConfigurationProperties("spring.datasource.druid.order2")
    40. // @ConditionalOnProperty(prefix = "spring.datasource.druid.order2", name = "enabled", havingValue = "true")
    41. // public DataSource order2DataSource(DruidProperties druidProperties)
    42. // {
    43. // DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
    44. // return druidProperties.dataSource(dataSource);
    45. // }
    46. @Bean(name = "shardingDataSource")
    47. public DataSource shardingDataSource(@Qualifier("shardDataSource") DataSource shardDataSource) throws SQLException
    48. {
    49. Map<String, DataSource> dataSourceMap = new HashMap<>();
    50. dataSourceMap.put("order", shardDataSource);
    51. // dataSourceMap.put("order2", order2DataSource);
    52. // sys_order 表规则配置
    53. // TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration("sys_order", "order$->{1..2}.sys_order_$->{0..1}");
    54. ShardingTableRuleConfiguration orderTableRuleConfig = new ShardingTableRuleConfiguration("sys_order", "order.sys_order_$->{0..1}");
    55. orderTableRuleConfig.setTableShardingStrategy(
    56. new StandardShardingStrategyConfiguration("order_id", "tableShardingAlgorithm"));
    57. // 配置分库策略
    58. // orderTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "order$->{user_id % 2 + 1}"));
    59. // 配置分表策略
    60. // orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "sys_order_$->{order_id % 2}"));
    61. // 分布式主键
    62. orderTableRuleConfig.setKeyGenerateStrategy(new KeyGenerateStrategyConfiguration("order_id", "snowflake"));
    63. // 配置分片规则
    64. ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
    65. shardingRuleConfig.getTables().add(orderTableRuleConfig);
    66. Properties pDatabase = new Properties();
    67. pDatabase.setProperty("shardCount", "2");
    68. // 设置分表策略
    69. ShardingSphereAlgorithmConfiguration ssactable = new ShardingSphereAlgorithmConfiguration(
    70. "ORDER_ID_SHARD", pDatabase);
    71. shardingRuleConfig.getShardingAlgorithms().put("tableShardingAlgorithm", ssactable);
    72. // 内置Snowflake分布式序列算法配置
    73. Properties snowflakeProp = new Properties();
    74. snowflakeProp.setProperty("worker-id", "1");
    75. shardingRuleConfig.getKeyGenerators().put("snowflake",
    76. new ShardingSphereAlgorithmConfiguration("SNOWFLAKE", snowflakeProp));
    77. // 获取数据源对象
    78. DataSource dataSource = ShardingSphereDataSourceFactory.createDataSource(dataSourceMap,
    79. Collections.singleton(shardingRuleConfig),
    80. getProperties());
    81. return dataSource;
    82. }
    83. /**
    84. * 系统参数配置
    85. */
    86. private Properties getProperties()
    87. {
    88. Properties shardingProperties = new Properties();
    89. shardingProperties.put("sql.show", true);
    90. return shardingProperties;
    91. }
    92. }

    7. druid配置类配置

    1. @Bean(name = "dynamicDataSource")
    2. @Primary
    3. public DynamicDataSource dataSource(DataSource masterDataSource)
    4. {
    5. Map<Object, Object> targetDataSources = new HashMap<>();
    6. targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
    7. setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
    8. setDataSource(targetDataSources, DataSourceType.SHARDING.name(), "shardingDataSource");
    9. return new DynamicDataSource(masterDataSource, targetDataSources);
    10. }

    8. 添加分表策略

    1. package com.ruoyi.framework.config;
    2. import java.util.Collection;
    3. import java.util.Properties;
    4. import java.util.regex.Matcher;
    5. import java.util.regex.Pattern;
    6. import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
    7. import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
    8. import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
    9. import org.slf4j.Logger;
    10. import org.slf4j.LoggerFactory;
    11. import org.springframework.beans.factory.annotation.Value;
    12. import org.springframework.stereotype.Component;
    13. @Component
    14. public class TableShardingAlgorithm implements StandardShardingAlgorithm<Long>{
    15. private static Logger log = LoggerFactory.getLogger(TableShardingAlgorithm.class);
    16. private Properties props;
    17. // @Value("${sharding.shardcount}")
    18. private Long shardCount = 2l;
    19. public Properties getProps() {
    20. return props;
    21. }
    22. public void setProps(Properties props) {
    23. this.props = props;
    24. }
    25. @Override
    26. public String doSharding(Collection<String> tableNames, PreciseShardingValue<Long> shardingValue) {
    27. Long lShard = 0l;
    28. lShard = (Long)shardingValue.getValue();
    29. // 读取设置的参数
    30. if(props != null)
    31. {
    32. String shardCountStr = props.getProperty("shardCount", "2");
    33. shardCount = Long.parseLong(shardCountStr);
    34. }
    35. Long lowMod = lShard % 2;
    36. Long shardTableMod = lowMod;
    37. // 转换为带格式的字符串
    38. String shardModStr = "_" + shardTableMod;
    39. for (String table : tableNames) {
    40. if (table.endsWith(shardModStr)) {
    41. return table;
    42. }
    43. }
    44. return "";
    45. }
    46. @Override
    47. public String getType() {
    48. // TODO Auto-generated method stub
    49. return "ORDER_ID_SHARD";
    50. }
    51. @Override
    52. public void init() {
    53. // TODO Auto-generated method stub
    54. }
    55. @Override
    56. public Collection<String> doSharding(Collection<String> tableNames,
    57. RangeShardingValue<Long> shardingValue) {
    58. return null;
    59. }
    60. }

    9. 通过spi设置分表策略

    在resource目录下创建META-INF\services目录,创建文件org.apache.shardingsphere.sharding.spi.ShardingAlgorithm,并在文件中添加如下内容:

    com.ruoyi.framework.config.TableShardingAlgorithm

    自定义的策略,需要通过spi机制进行配置。 

    10. 在服务的实现文件中添加注解

    通过注解@DataSource(DataSourceType.SHARDING),框架可以判断对应的操作需要使用分表的数据库连接。

    1. package com.ruoyi.system.service.impl;
    2. import java.util.List;
    3. import com.ruoyi.common.annotation.DataSource;
    4. import com.ruoyi.common.enums.DataSourceType;
    5. import org.springframework.beans.factory.annotation.Autowired;
    6. import org.springframework.stereotype.Service;
    7. import com.ruoyi.system.mapper.SysOrderMapper;
    8. import com.ruoyi.system.domain.SysOrder;
    9. import com.ruoyi.system.service.ISysOrderService;
    10. import com.ruoyi.common.core.text.Convert;
    11. /**
    12. * 订单信息Service业务层处理
    13. *
    14. * @author ruoyi
    15. * @date 2022-06-27
    16. */
    17. @Service
    18. public class SysOrderServiceImpl implements ISysOrderService
    19. {
    20. @Autowired
    21. private SysOrderMapper sysOrderMapper;
    22. /**
    23. * 查询订单信息
    24. *
    25. * @param orderId 订单信息主键
    26. * @return 订单信息
    27. */
    28. @Override
    29. @DataSource(DataSourceType.SHARDING)
    30. public SysOrder selectSysOrderByOrderId(Long orderId)
    31. {
    32. return sysOrderMapper.selectSysOrderByOrderId(orderId);
    33. }
    34. /**
    35. * 查询订单信息列表
    36. *
    37. * @param sysOrder 订单信息
    38. * @return 订单信息
    39. */
    40. @Override
    41. @DataSource(DataSourceType.SHARDING)
    42. public List<SysOrder> selectSysOrderList(SysOrder sysOrder)
    43. {
    44. return sysOrderMapper.selectSysOrderList(sysOrder);
    45. }
    46. /**
    47. * 新增订单信息
    48. *
    49. * @param sysOrder 订单信息
    50. * @return 结果
    51. */
    52. @Override
    53. @DataSource(DataSourceType.SHARDING)
    54. public int insertSysOrder(SysOrder sysOrder)
    55. {
    56. return sysOrderMapper.insertSysOrder(sysOrder);
    57. }
    58. /**
    59. * 修改订单信息
    60. *
    61. * @param sysOrder 订单信息
    62. * @return 结果
    63. */
    64. @Override
    65. @DataSource(DataSourceType.SHARDING)
    66. public int updateSysOrder(SysOrder sysOrder)
    67. {
    68. return sysOrderMapper.updateSysOrder(sysOrder);
    69. }
    70. /**
    71. * 批量删除订单信息
    72. *
    73. * @param orderIds 需要删除的订单信息主键
    74. * @return 结果
    75. */
    76. @Override
    77. @DataSource(DataSourceType.SHARDING)
    78. public int deleteSysOrderByOrderIds(String orderIds)
    79. {
    80. return sysOrderMapper.deleteSysOrderByOrderIds(Convert.toStrArray(orderIds));
    81. }
    82. /**
    83. * 删除订单信息信息
    84. *
    85. * @param orderId 订单信息主键
    86. * @return 结果
    87. */
    88. @Override
    89. @DataSource(DataSourceType.SHARDING)
    90. public int deleteSysOrderByOrderId(Long orderId)
    91. {
    92. return sysOrderMapper.deleteSysOrderByOrderId(orderId);
    93. }
    94. }

    11. 执行测试

    通过页面,可以添加和删除数据,在数据库表中,可以看到数据被保存到不同的表中了。

    表sys_order_0中的数据:

    表sys_order_1中的数据: 

     

     可以看出尾数为奇数的数据到了sys_order_1,尾数为偶数的数据到了sys_order_0。

  • 相关阅读:
    7.3 服务端漏洞:密码找回逻辑漏洞检测和重现
    three.js中直线的创建,以及new THREE.LineBasicMaterial不能设置宽度问题。
    某云负载均衡获取客户端真实IP的问题
    三家前装出货超2万台,激光雷达明年「放量」是大概率事件
    ros2原来本是一个通信协议
    C语言中获得结构体成员的相对偏移量(Linux内核源码解读)
    疯了!全网居然有人一次性把Java虚拟机HotSpot 给讲透彻了
    Eigen中三维位姿表示方式以及相互转换
    目标检测中生成锚框函数详解
    SpringCloudAlibaba系列微服务搭建笔记二-RestTemplate+Ribbon
  • 原文地址:https://blog.csdn.net/liaomingwu/article/details/125482377