• sharding-jdbc实现分库分表


    一、ShardingSphere介绍

      ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成。 他们均提供标准化的数据分片、分布式事务和数据库治理功能,可适用于如Java同构、异构语言、云原生等各种多样化的应用场景。详细一点的介绍直接看官网:概览 :: ShardingSphere

    二、关于分库分表的思考

    1、分库分表为了什么?

    分库分表就是为了解决由于数据量过大而导致数据库性能(IO瓶颈,CPU瓶颈)降低的问题,将原来独立的数据库拆分成若干数据库组成 ,将数据大表拆分成若干数据表组成,使得单一数据库、单一数据表的数据量变小,从而达到提升数据库性能的目的。

    2、数据库的分区、垂直分库、垂直分表、水平分库、水平分表各自解决那些问题?

    • 分区表

      • 分区表的分区方式有range、list、hash、key四种方式,但常用的是range、list方式
      • 分区表可以单独对分区数据进行操作,在特定的场景下,方便对数据的老化和查询
      • 分区表可以提高单表的存储,并且数据还可以分布在不同的物理设备上
    • 垂直分库

      • 解决业务层面的耦合,业务清晰
      • 能对不同业务的数据进行分级管理、维护、监控、扩展等
      • 高并发场景下,垂直分库一定程度的提升IO、数据库连接数、降低单机硬件资源的瓶颈
    • 垂直分表(将一张表拆成多张表)

      • 为了避免IO争抢并减少锁表的几率
      • 充分发挥热数据的操作效率
      • 可以把不常用的字段单独放在一张表,如一些详细信息以及text,blob等大字段
    • 水平分库

      • 解决了单库大数据,高并发的性能瓶颈
      • 提高了系统的稳定性及可用性
    • 水平分表

      • 优化单一表数据量过大而产生的性能问题
      • 避免IO争抢并减少锁表的几率

    3、分库分表的策略一般在什么情况下使用,使用哪种?

    • 首先一般来说,在系统设计阶段就应该根据业务耦合松紧来确定垂直分库、垂直分表的方案。
    • 当数据量随着业务凉的提升不断增大,但访问压力还不是特别大的情况下,我们首先考虑缓存、读写分离、索引等技术方案。
    • 当数据量增长到特别大且持续增长时,即将或者已经出现性能瓶颈时,再考虑水平分库水平分表的方案。

    4、水平分库表如何解决扩容、热点问题?

    • 最好的方式莫过于设计前期对数据量的正确预估和业务场景的判断,尽量避免后期出现热点问题和扩容问题。
    • 对于通过hash取模方案,没有热点问题,但会出现扩容问题,解决方案有:
      • 停服迁移
      • 升级从库
      • 双写迁移
    • 对于通过range方案,无需迁移数据,但肯能出现热点问题。所以在实际业务中,我们可以通过range+hash的配合使用来达到即支持扩容又尽可能避免热点。

    5、分库分表如何解决跨库事务?

    • 2PC两阶段提交协议
    • TCC事务补偿机制
    • 最终一致性方案
    • 最大努力通知型

    三、Springboot整合ShardingJDBC

    方式一:基于配置文件集成,方便简单但是不够灵活,代码:https://github.com/xianlongbai/sharding-jdbc-boot-demo

    方式二:这里我们主要基于java config的方式来集成到springboot

    1、pom.xml模块添加sharding-jdbc整合依赖

    1. org.springframework.boot
    2. spring-boot-starter-web
    3. org.mybatis.spring.boot
    4. mybatis-spring-boot-starter
    5. 2.2.2
    6. org.springframework.boot
    7. spring-boot-starter-aop
    8. org.springframework.boot
    9. spring-boot-starter-test
    10. junit
    11. junit
    12. 4.13.1
    13. javax.servlet
    14. javax.servlet-api
    15. org.apache.commons
    16. commons-lang3
    17. com.alibaba.fastjson2
    18. fastjson2
    19. 2.0.10
    20. org.projectlombok
    21. lombok
    22. 1.18.8
    23. mysql
    24. mysql-connector-java
    25. runtime
    26. org.springframework.boot
    27. spring-boot-starter-test
    28. test
    29. com.alibaba
    30. druid-spring-boot-starter
    31. 1.2.4
    32. org.apache.shardingsphere
    33. sharding-jdbc-core
    34. 4.1.1

    2、创建两个测试数据库

    1. create database `ry-order1`;
    2. create database `ry-order2`;

    3、创建两个测试订单表

    1. -- ----------------------------
    2. -- 订单信息表sys_order_0
    3. -- ----------------------------
    4. drop table if exists sys_order_0;
    5. create table sys_order_0
    6. (
    7. order_id bigint(20) not null comment '订单ID',
    8. user_id bigint(64) not null comment '用户编号',
    9. status char(1) not null comment '状态(0交易成功 1交易失败)',
    10. order_no varchar(64) default null comment '订单流水',
    11. primary key (order_id)
    12. ) engine=innodb comment = '订单信息表';
    13. -- ----------------------------
    14. -- 订单信息表sys_order_1
    15. -- ----------------------------
    16. drop table if exists sys_order_1;
    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添加测试数据源

    application.yml文件

    1. server:
    2. # 服务器的HTTP端口,默认为80
    3. port: 8080
    4. servlet:
    5. # 应用的访问路径
    6. context-path: /
    7. # Spring配置
    8. spring:
    9. #加载application-druid.yml文件
    10. profiles:
    11. active: druid
    12. # MyBatis
    13. mybatis:
    14. # 搜索指定包别名
    15. typeAliasesPackage: com.common.pojo
    16. # 配置mapper的扫描,找到所有的mapper.xml映射文件
    17. mapperLocations: classpath*:mapper/**/*Mapper.xml
    18. # 加载全局的配置文件
    19. # #configLocation: classpath:mybatis/mybatis-config.xml

    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/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    10. username: root
    11. password: 123456
    12. # 订单库1
    13. order1:
    14. enabled: true
    15. url: jdbc:mysql://localhost:3306/ry-order1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    16. username: root
    17. password: 123456
    18. # 订单库2
    19. order2:
    20. enabled: true
    21. url: jdbc:mysql://localhost:3306/ry-order2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
    22. username: root
    23. password: 123456
    24. # 初始连接数
    25. initialSize: 5
    26. # 最小连接池数量
    27. minIdle: 10
    28. # 最大连接池数量
    29. maxActive: 20
    30. # 配置获取连接等待超时的时间
    31. maxWait: 60000
    32. # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
    33. timeBetweenEvictionRunsMillis: 60000
    34. # 配置一个连接在池中最小生存的时间,单位是毫秒
    35. minEvictableIdleTimeMillis: 300000
    36. # 配置一个连接在池中最大生存的时间,单位是毫秒
    37. maxEvictableIdleTimeMillis: 900000
    38. # 配置检测连接是否有效
    39. validationQuery: SELECT 1 FROM DUAL
    40. testWhileIdle: true
    41. testOnBorrow: false
    42. testOnReturn: false
    43. webStatFilter:
    44. enabled: true
    45. statViewServlet:
    46. enabled: true
    47. # 设置白名单,不填则允许所有访问
    48. allow:
    49. url-pattern: /druid/*
    50. # 控制台管理用户名和密码
    51. login-username: admin
    52. login-password: 123456
    53. filter:
    54. stat:
    55. enabled: true
    56. # 慢SQL记录
    57. log-slow-sql: true
    58. slow-sql-millis: 1000
    59. merge-sql: true
    60. wall:
    61. config:
    62. multi-statement-allow: true

    5、数据源切换处理

    1. import org.slf4j.Logger;
    2. import org.slf4j.LoggerFactory;
    3. /**
    4. * 数据源切换处理
    5. */
    6. public class DynamicDataSourceContextHolder {
    7. public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
    8. /**
    9. * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
    10. * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
    11. */
    12. private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>();
    13. /**
    14. * 设置数据源的变量
    15. */
    16. public static void setDataSourceType(String dsType) {
    17. log.info("切换到{}数据源", dsType);
    18. CONTEXT_HOLDER.set(dsType);
    19. }
    20. /**
    21. * 获得数据源的变量
    22. */
    23. public static String getDataSourceType() {
    24. return CONTEXT_HOLDER.get();
    25. }
    26. /**
    27. * 清空数据源变量
    28. */
    29. public static void clearDataSourceType() {
    30. CONTEXT_HOLDER.remove();
    31. }
    32. }

    6、动态数据源切换

    通过AbstractRoutingDataSource实现数据源动态切换
    Springboot提供了AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,这样我们可以在执行查询之前,切换到需要的数据源。实现可动态路由的数据源,在每次数据库查询操作前执行。它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源。
     

    1. import com.common.utils.DynamicDataSourceContextHolder;
    2. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    3. import javax.sql.DataSource;
    4. import java.util.Map;
    5. /**
    6. * 动态数据源切换
    7. */
    8. public class DynamicDataSource extends AbstractRoutingDataSource {
    9. public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) {
    10. super.setDefaultTargetDataSource(defaultTargetDataSource);
    11. super.setTargetDataSources(targetDataSources);
    12. super.afterPropertiesSet();
    13. }
    14. @Override
    15. protected Object determineCurrentLookupKey() {
    16. return DynamicDataSourceContextHolder.getDataSourceType();
    17. }
    18. }

    7、自定义数据源切换注解

    1. import com.common.enums.DataSourceType;
    2. import java.lang.annotation.*;
    3. /**
    4. * 自定义多数据源切换注解
    5. *

    6. * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
    7. */
    8. @Target({ElementType.METHOD, ElementType.TYPE})
    9. @Retention(RetentionPolicy.RUNTIME)
    10. @Documented
    11. @Inherited
    12. public @interface DataSource {
    13. /**
    14. * 切换数据源名称
    15. */
    16. public DataSourceType value() default DataSourceType.MASTER;
    17. }
    1. /**
    2. * 数据源
    3. *
    4. */
    5. public enum DataSourceType {
    6. /**
    7. * 主库
    8. */
    9. MASTER,
    10. /**
    11. * 从库
    12. */
    13. SLAVE,
    14. /**
    15. * 分库分表
    16. */
    17. SHARDING
    18. }

    8、druid配置属性

    1. /**
    2. * druid 配置属性
    3. */
    4. @Configuration
    5. public class DruidProperties {
    6. @Value("${spring.datasource.druid.initialSize}")
    7. private int initialSize;
    8. @Value("${spring.datasource.druid.minIdle}")
    9. private int minIdle;
    10. @Value("${spring.datasource.druid.maxActive}")
    11. private int maxActive;
    12. @Value("${spring.datasource.druid.maxWait}")
    13. private int maxWait;
    14. @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
    15. private int timeBetweenEvictionRunsMillis;
    16. @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
    17. private int minEvictableIdleTimeMillis;
    18. @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
    19. private int maxEvictableIdleTimeMillis;
    20. @Value("${spring.datasource.druid.validationQuery}")
    21. private String validationQuery;
    22. @Value("${spring.datasource.druid.testWhileIdle}")
    23. private boolean testWhileIdle;
    24. @Value("${spring.datasource.druid.testOnBorrow}")
    25. private boolean testOnBorrow;
    26. @Value("${spring.datasource.druid.testOnReturn}")
    27. private boolean testOnReturn;
    28. public DruidDataSource dataSource(DruidDataSource datasource) {
    29. /** 配置初始化大小、最小、最大 */
    30. datasource.setInitialSize(initialSize);
    31. datasource.setMaxActive(maxActive);
    32. datasource.setMinIdle(minIdle);
    33. /** 配置获取连接等待超时的时间 */
    34. datasource.setMaxWait(maxWait);
    35. /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
    36. datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
    37. /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
    38. datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
    39. datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
    40. /**
    41. * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
    42. */
    43. datasource.setValidationQuery(validationQuery);
    44. /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
    45. datasource.setTestWhileIdle(testWhileIdle);
    46. /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
    47. datasource.setTestOnBorrow(testOnBorrow);
    48. /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
    49. datasource.setTestOnReturn(testOnReturn);
    50. return datasource;
    51. }
    52. }

    9、多数据源配置

    1. import com.alibaba.druid.pool.DruidDataSource;
    2. import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
    3. import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
    4. import com.alibaba.druid.util.Utils;
    5. import com.common.config.properties.DruidProperties;
    6. import com.common.datasource.DynamicDataSource;
    7. import com.common.enums.DataSourceType;
    8. import com.common.utils.SpringUtils;
    9. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    10. import org.springframework.boot.context.properties.ConfigurationProperties;
    11. import org.springframework.boot.web.servlet.FilterRegistrationBean;
    12. import org.springframework.context.annotation.Bean;
    13. import org.springframework.context.annotation.Configuration;
    14. import org.springframework.context.annotation.Primary;
    15. import javax.servlet.*;
    16. import javax.sql.DataSource;
    17. import java.io.IOException;
    18. import java.util.HashMap;
    19. import java.util.Map;
    20. /**
    21. * druid 配置多数据源
    22. *
    23. */
    24. @Configuration
    25. public class DruidConfig {
    26. @Bean
    27. @ConfigurationProperties("spring.datasource.druid.master")
    28. public DataSource masterDataSource(DruidProperties druidProperties) {
    29. DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
    30. return druidProperties.dataSource(dataSource);
    31. }
    32. @Bean
    33. @ConfigurationProperties("spring.datasource.druid.slave")
    34. @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
    35. public DataSource slaveDataSource(DruidProperties druidProperties) {
    36. DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
    37. return druidProperties.dataSource(dataSource);
    38. }
    39. @Bean(name = "dynamicDataSource")
    40. @Primary
    41. public DynamicDataSource dataSource(DataSource masterDataSource) {
    42. Map targetDataSources = new HashMap<>();
    43. targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
    44. setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
    45. setDataSource(targetDataSources, DataSourceType.SHARDING.name(), "shardingDataSource");
    46. return new DynamicDataSource(masterDataSource, targetDataSources);
    47. }
    48. /**
    49. * 设置数据源
    50. *
    51. * @param targetDataSources 备选数据源集合
    52. * @param sourceName 数据源名称
    53. * @param beanName bean名称
    54. */
    55. public void setDataSource(Map targetDataSources, String sourceName, String beanName) {
    56. try {
    57. DataSource dataSource = SpringUtils.getBean(beanName);
    58. targetDataSources.put(sourceName, dataSource);
    59. } catch (Exception e) {
    60. }
    61. }
    62. /**
    63. * 去除监控页面底部的广告
    64. */
    65. @SuppressWarnings({"rawtypes", "unchecked"})
    66. @Bean
    67. @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
    68. public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) {
    69. // 获取web监控页面的参数
    70. DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
    71. // 提取common.js的配置路径
    72. String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
    73. String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
    74. final String filePath = "support/http/resources/js/common.js";
    75. // 创建filter进行过滤
    76. Filter filter = new Filter() {
    77. @Override
    78. public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
    79. }
    80. @Override
    81. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    82. throws IOException, ServletException {
    83. chain.doFilter(request, response);
    84. // 重置缓冲区,响应头不会被重置
    85. response.resetBuffer();
    86. // 获取common.js
    87. String text = Utils.readFromResource(filePath);
    88. // 正则替换banner, 除去底部的广告信息
    89. text = text.replaceAll("
      "
      , "");
    90. text = text.replaceAll("powered.*?shrek.wang", "");
    91. response.getWriter().write(text);
    92. }
    93. @Override
    94. public void destroy() {
    95. }
    96. };
    97. FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    98. registrationBean.setFilter(filter);
    99. registrationBean.addUrlPatterns(commonJsPattern);
    100. return registrationBean;
    101. }
    102. }

    10、分库分表配置

    1. import com.alibaba.druid.pool.DruidDataSource;
    2. import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
    3. import com.common.config.properties.DruidProperties;
    4. import com.common.sharding.ShardingAlgorithm;
    5. import org.apache.shardingsphere.api.config.sharding.KeyGeneratorConfiguration;
    6. import org.apache.shardingsphere.api.config.sharding.ShardingRuleConfiguration;
    7. import org.apache.shardingsphere.api.config.sharding.TableRuleConfiguration;
    8. import org.apache.shardingsphere.api.config.sharding.strategy.InlineShardingStrategyConfiguration;
    9. import org.apache.shardingsphere.api.config.sharding.strategy.StandardShardingStrategyConfiguration;
    10. import org.apache.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
    11. import org.springframework.beans.factory.annotation.Qualifier;
    12. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    13. import org.springframework.boot.context.properties.ConfigurationProperties;
    14. import org.springframework.context.annotation.Bean;
    15. import org.springframework.context.annotation.Configuration;
    16. import javax.sql.DataSource;
    17. import java.sql.SQLException;
    18. import java.util.HashMap;
    19. import java.util.Map;
    20. import java.util.Properties;
    21. /**
    22. * sharding 配置信息
    23. */
    24. @Configuration
    25. public class ShardingDataSourceConfig {
    26. @Bean
    27. @ConfigurationProperties("spring.datasource.druid.order1")
    28. @ConditionalOnProperty(prefix = "spring.datasource.druid.order1", name = "enabled", havingValue = "true")
    29. public DataSource order1DataSource(DruidProperties druidProperties) {
    30. DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
    31. return druidProperties.dataSource(dataSource);
    32. }
    33. @Bean
    34. @ConfigurationProperties("spring.datasource.druid.order2")
    35. @ConditionalOnProperty(prefix = "spring.datasource.druid.order2", name = "enabled", havingValue = "true")
    36. public DataSource order2DataSource(DruidProperties druidProperties) {
    37. DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
    38. return druidProperties.dataSource(dataSource);
    39. }
    40. // @Bean(name = "shardingDataSource")
    41. // public DataSource shardingDataSource(@Qualifier("order1DataSource") DataSource order1DataSource, @Qualifier("order2DataSource") DataSource order2DataSource) throws SQLException {
    42. // Map dataSourceMap = new HashMap<>();
    43. // dataSourceMap.put("order1", order1DataSource);
    44. // dataSourceMap.put("order2", order2DataSource);
    45. //
    46. // // sys_order 表规则配置 (Groovy表达式)
    47. // TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration("sys_order", "order$->{1..2}.sys_order_$->{0..1}");
    48. //
    49. // // 配置分库策略
    50. // orderTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "order$->{user_id % 2 + 1}"));
    51. // // 配置分表策略
    52. // orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "sys_order_$->{order_id % 2}"));
    53. // // 分布式主键
    54. // orderTableRuleConfig.setKeyGeneratorConfig(new KeyGeneratorConfiguration("SNOWFLAKE", "order_id"));
    55. //
    56. // // 配置分片规则
    57. // ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
    58. // shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);
    59. //
    60. // // 数据库分片策略
    61. // shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new StandardShardingStrategyConfiguration("user_id", new ShardingAlgorithm()));
    62. //
    63. // //系统参数配置
    64. // Properties shardingProperties = new Properties();
    65. // shardingProperties.put("sql.show", true);
    66. //
    67. // // 获取数据源对象
    68. // DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, shardingProperties);
    69. // return dataSource;
    70. // }
    71. @Bean(name = "shardingDataSource")
    72. public DataSource shardingDataSource(@Qualifier("order1DataSource") DataSource order1DataSource, @Qualifier("order2DataSource") DataSource order2DataSource) throws SQLException {
    73. Map dataSourceMap = new HashMap<>();
    74. dataSourceMap.put("order1", order1DataSource);
    75. dataSourceMap.put("order2", order2DataSource);
    76. //表规则配置
    77. TableRuleConfiguration tableRuleConfiguration = new TableRuleConfiguration("sys_order", "order$->{1..2}.sys_order_$->{0..1}");
    78. //分库
    79. tableRuleConfiguration.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "order$->{user_id % 2 + 1}"));
    80. // 配置分表策略
    81. //orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "sys_order_$->{order_id % 2}"));
    82. //自定义分表规则
    83. tableRuleConfiguration.setTableShardingStrategyConfig(new StandardShardingStrategyConfiguration("order_id", new ShardingAlgorithm()));
    84. // 分布式主键
    85. tableRuleConfiguration.setKeyGeneratorConfig(new KeyGeneratorConfiguration("SNOWFLAKE", "order_id"));
    86. //设置表复杂sharding规则
    87. // TableRuleConfiguration orderInfoTableRule = new TableRuleConfiguration("order_info");
    88. // ComplexShardingStrategyConfiguration complexShardingStrategyConfiguration =
    89. // new ComplexShardingStrategyConfiguration("order_no,merchant_id",
    90. // new ComplexDatabaseShardingAlgorithm());
    91. // orderInfoTableRule.setDatabaseShardingStrategyConfig(complexShardingStrategyConfiguration);
    92. ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
    93. shardingRuleConfig.getTableRuleConfigs().add(tableRuleConfiguration);
    94. // shardingRuleConfig.getTableRuleConfigs().add(orderInfoTableRule);
    95. //系统参数配置
    96. Properties properties = new Properties();
    97. properties.put("sql.show", true);
    98. return ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, properties);
    99. }
    100. }

    11、分库分表测试

    业务处理层

    1. import com.common.annotation.DataSource;
    2. import com.common.enums.DataSourceType;
    3. import com.common.mapper.SysOrderMapper;
    4. import com.common.pojo.SysOrder;
    5. import com.common.service.ISysOrderService;
    6. import org.springframework.beans.factory.annotation.Autowired;
    7. import org.springframework.stereotype.Service;
    8. import java.util.List;
    9. /**
    10. * 订单Service业务层处理
    11. */
    12. @Service
    13. public class SysOrderServiceImpl implements ISysOrderService {
    14. @Autowired
    15. private SysOrderMapper myShardingMapper;
    16. /**
    17. * 查询订单
    18. *
    19. * @param orderId 订单编号
    20. * @return 订单信息
    21. */
    22. @Override
    23. @DataSource(DataSourceType.SHARDING)
    24. public SysOrder selectSysOrderById(Long orderId) {
    25. return myShardingMapper.selectSysOrderById(orderId);
    26. }
    27. /**
    28. * 查询订单列表
    29. *
    30. * @param sysOrder 订单信息
    31. * @return 订单列表
    32. */
    33. @Override
    34. @DataSource(DataSourceType.SHARDING)
    35. public List selectSysOrderList(SysOrder sysOrder) {
    36. return myShardingMapper.selectSysOrderList(sysOrder);
    37. }
    38. /**
    39. * 新增订单
    40. *
    41. * @param sysOrder 订单
    42. * @return 结果
    43. */
    44. @Override
    45. @DataSource(DataSourceType.SHARDING)
    46. public int insertSysOrder(SysOrder sysOrder) {
    47. return myShardingMapper.insertSysOrder(sysOrder);
    48. }
    49. }

    controller

    1. import com.common.pojo.SysOrder;
    2. import com.common.service.ISysOrderService;
    3. import com.common.utils.ResponseUtils;
    4. import org.springframework.beans.factory.annotation.Autowired;
    5. import org.springframework.web.bind.annotation.GetMapping;
    6. import org.springframework.web.bind.annotation.PathVariable;
    7. import org.springframework.web.bind.annotation.RequestMapping;
    8. import org.springframework.web.bind.annotation.RestController;
    9. import java.util.UUID;
    10. /**
    11. * 订单 Controller
    12. */
    13. @RestController
    14. @RequestMapping("/order")
    15. public class SysOrderController {
    16. @Autowired
    17. private ISysOrderService sysOrderService;
    18. @GetMapping("/add/{userId}")
    19. public ResponseUtils add(@PathVariable("userId") Long userId) {
    20. SysOrder sysOrder = new SysOrder();
    21. sysOrder.setUserId(userId);
    22. sysOrder.setStatus("0");
    23. sysOrder.setOrderNo(UUID.randomUUID().toString());
    24. return ResponseUtils.success(sysOrderService.insertSysOrder(sysOrder));
    25. }
    26. @GetMapping("/list")
    27. public ResponseUtils list() {
    28. return ResponseUtils.success(sysOrderService.selectSysOrderList(new SysOrder()));
    29. }
    30. @GetMapping("/query/{orderId}")
    31. public ResponseUtils query(@PathVariable("orderId") Long orderId) {
    32. return ResponseUtils.success(sysOrderService.selectSysOrderById(orderId));
    33. }
    34. }

    测试验证

    访问http://localhost:8080/order/add/1入库到ry-order2

    访问http://localhost:8080/order/add/2入库到ry-order1

    同时根据订单号order_id % 2入库到sys_order_0或者sys_order_1

    11、源码下载

    https://gitee.com/wdae/sharding-jdbc-demo-master.git

  • 相关阅读:
    如何伪造http头,让后端认为是本地访问
    信息系统项目管理师(高项)01
    Shell判断:流程控制—if(三)
    IOTE 2023盛况回顾,美格智能聚连接之力促数字新生长
    UE4_材质_湿度着色器及Desaturation算法_ben材质教程
    java spring security oauth2 动态 修改当前登录用户的基础信息以及权限2.0(无需重新登录)
    模型调参优化
    BigDecimal 类型的计算方法
    mysql 统计当天,当周,当月,当年和总量的SQL语句如何写?
    企业架构LNMP学习笔记37
  • 原文地址:https://blog.csdn.net/qq_40428665/article/details/126953144