自定义水平分库分表策略【hint分片】

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 自定义水平分库分表策略【hint分片】

公众号merlinsea


背景

   在之前的公众号文章中,不管是自定义范围分片策略还是精准分片策略,其分片键的值都是直接从sql语句中解析出来。如果有这样一个sql需要:select * from product_order where out_trade_no='fdjaslkji394298';只需要路由到ds1数据库的product_order_0表中,不需要广播到所有的表。那么这个需求无法通过之前的方式实现,因为这条sql语句中没有用到分片键。这时候就需要使用到hint分片策略。


hint分片策略介绍

   hint的中文意思:提示、暗示;

   这种分片策略无需配置文件进行配置分片健,分片健值也不再从 SQL中解析【外部手动在业务逻辑代码中指定分片健值】做为分库分表依据, 让 SQL在指定的分库、分表中执行;

   通过Hint代码指定的方式而非SQL解析的方式分片的策略;

   Hint策略会绕过SQL解析的,对于这些比较复杂的需要分片的查询,Hint分片策略性能可能会更好;

   可以让不涉及分片键的sql去指定的某个库某个表进行执行。


1、编写Hint分库的策略类,实现HintShardingAlgorithm<T>  T代表需要用到的分片值的类型


public class CustomDBHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
    /**
     *
     * @param dataSourceNames 数据源集合
     *                      在分库时值为所有分片库的集合 databaseNames
     *                      分表时为对应分片库中所有分片表的集合 tablesNames
     *
     * @param hintShardingValue  分片属性,包括
     *                                  logicTableName 为逻辑表,
     *                                  columnName 分片健(字段),hint策略此处为空 ""
     *
     *                                  value 【之前】都是 从 SQL 中解析出的分片健的值,用于取模判断
     *                                   HintShardingAlgorithm不再从SQL 解析中获取值,而是直接通过
     *                                   hintManager.addTableShardingValue("product_order", 1)参数进行指定
     * @return
     */
    @Override
    public Collection<String> doSharding(Collection<String> dataSourceNames, HintShardingValue<Long> hintShardingValue) {
        Collection<String> result = new ArrayList<>();
        for(String datasourceName: dataSourceNames){
            for(Long shardingValue : hintShardingValue.getValues()){
                //通过传入的指定分片value%数据源length 得到应该命中哪个库
                String value = shardingValue % dataSourceNames.size()+"";
                if(datasourceName.endsWith(value)){
                    result.add(datasourceName);
                }
            }
        }
        return result;
    }
}


2、编写编写Hint分表的策略类,实现HintShardingAlgorithm<T>  T代表需要用到的分片值的类型

public class CustomTableHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
    /**
     *
     * @param dataSourceNames 数据源集合
     *                      在分库时值为所有分片库的集合 databaseNames
     *                      分表时为对应分片库中所有分片表的集合 tablesNames
     *
     * @param hintShardingValue  分片属性,包括
     *                                  logicTableName 为逻辑表,
     *                                  columnName 分片健(字段),hint策略此处为空 ""
     *
     *                                  value 【之前】都是 从 SQL 中解析出的分片健的值,用于取模判断
     *                                   HintShardingAlgorithm不再从SQL 解析中获取值,而是直接通过
     *                                   hintManager.addTableShardingValue("product_order", 1)参数进行指定
     * @return
     */
    @Override
    public Collection<String> doSharding(Collection<String> dataSourceNames, HintShardingValue<Long> hintShardingValue) {
        Collection<String> result = new ArrayList<>();
        for(String datasourceName: dataSourceNames){
            for(Long shardingValue : hintShardingValue.getValues()){
                //通过传入的指定分片value%数据源length 得到应该命中哪个表
                String value = shardingValue % dataSourceNames.size()+"";
                if(datasourceName.endsWith(value)){
                    result.add(datasourceName);
                }
            }
        }
        return result;
    }
}


3、编写application.properties

spring.application.name=xdclass-sharding-jdbc
server.port=8080
# 打印执行的数据库以及语句
spring.shardingsphere.props.sql.show=true
# 数据源 db0
spring.shardingsphere.datasource.names=ds0,ds1
# 第一个数据库
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://localhost:3306/xdclass_shop_order_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=liangmerlin1025
# 第二个数据库
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://localhost:3306/xdclass_shop_order_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=liangmerlin1025
#配置workId
spring.shardingsphere.sharding.tables.product_order.key-generator.props.worker.id=1
#id生成策略
spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
#精准分片-水平分表
# 指定真实节点,配置数据节点,在 Spring 环境中建议使用 $->{...}
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds$->{0..1}.product_order_$->{0..1}
#hint分库策略
spring.shardingsphere.sharding.tables.product_order.database-strategy.hint.algorithm-class-name=net.xdclass.strategy.CustomDBHintShardingAlgorithm
#hint分表策略
spring.shardingsphere.sharding.tables.product_order.table-strategy.hint.algorithm-class-name=net.xdclass.strategy.CustomTableHintShardingAlgorithm


4、业务代码编写如下:

这里是和前两种从sql解析分片键值的分片策略最大的不同,即需要手动指定当前这条sql的分片键值。然后在执行sql的时候就只会路由指定的表

/**
 * 正常可以用AOP进行实现清除历史规则,真实业务中分片分表的键值可以由外界传入
 */
@Test
public void testHit(){
    //清除历史规则
    HintManager.clear();
    //获取对应的实例
    HintManager hintManager = HintManager.getInstance();
    //设置库的分片键值,value=3是用于库分片取模,通过分片逻辑命中ds1库
    hintManager.addDatabaseShardingValue("product_order",3L);
    //设置表的分片键值,value=8是用于表分片取模,通过分片逻辑命中product_order_0表
    hintManager.addTableShardingValue("product_order",8L);
    //如果在读写分离数据库中,Hint 可以强制读主库(主从复制存在一定延时,但在业务场景中,可能更需要保证数据的实时性)
    //hintManager.setMasterRouteOnly();
    //对应sql语句的id值不做为分片键的值,仅仅只有查询功能
    productOrderMapper.selectList(new QueryWrapper<ProductOrderDO>().eq("id",66L));
}


通过运行发现,这条sql确实只是命中了ds1库的product_order_0表

640.jpg


关于leetcode算法训练营:

   加我微信号私聊参加训练营,尤其是想进入大厂工作的同学,算法是绕不过去的坎,我自己花了三年时间刷算法,总结思路,刷各种数据结构课程,加入我的训练营,我手把手以在线直播课的形式带你理思路,手把手带你写代码,让你真正体会算法之美~,同时遇到不明白的地方可以直接课上和我沟通,彻底解决你的代码困难症~

本人用c++刷了800道左右的算法,java语言刷了600道左右的算法题,并对这些题做了详细的个人总结。本科期间系统学习了数据结构与算法课程,同时考研过程中写完了率辉主编的《2020年数据结构高分笔记》和《数据结构1000题》,看完的视频包括《mooc浙大数据结构国家精品课程》和《王道考研408数据结构课程》,《王道2019年算法题讲解视频》,最终以初试专业第三名进入了北理工软件工程专业。熟悉并掌握常见的数据结构,比如链表、数组、树、图、队列、堆栈等等,精通数据结构教材中的所有算法,比如常见的遍历算法、动态规划,递归,回溯,剪枝,并查集,最短路径,拓扑排序等,所以快加入训练营吧,我们一起进步

奔跑的小梁,公众号:梁霖编程工具库我决定了,算法文档开源!!
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
12月前
|
消息中间件 监控 Java
RocketMQ 同步发送、异步发送和单向发送,如何选择?
本文详细分析了 RocketMQ 中同步发送、异步发送和单向发送三种消息发送方式的原理、优缺点及适用场景。同步发送可靠性高但延迟较大,适合订单系统等场景;异步发送非阻塞且延迟低,适用于实时数据处理等场景;单向发送高效但可靠性低,适用于日志收集等场景。文章还提供了示例代码和核心源码分析,帮助读者更好地理解每种发送方式的特点。
1695 4
|
移动开发 Java API
大疆无人机对接
本文介绍了大疆无人机对接第三方云平台的方案,包括设备对接和CloudAPI对接两种方式,重点讨论了CloudAPI对接。CloudAPI对接方案通过DJI Pilot 2或大疆机场将无人机与第三方云平台连接,实现低门槛接入,无需重复开发APP。方案优势在于让开发者更专注于业务开发,而非无人机功能适配。文章详细阐述了对接流程,包括环境准备、申请APPKey、对接流程、直播功能及获取无人机实时数据等内容,并提供了丰富的接口说明和技术支持资源。
6552 4
大疆无人机对接
|
监控 Cloud Native 关系型数据库
【跨区域PolarDB-MySQL主备互通】:揭秘如何跨越万里实现数据无缝同步,打造坚不可摧的灾备体系!
【8月更文挑战第20天】阿里云PolarDB是一款兼容MySQL协议的云原生数据库服务,提供高性能与高可用性。本文介绍如何在PolarDB-MySQL中实现跨区域主备同步。首先创建主备两个集群,接着通过MySQL复制功能配置同步:获取主节点复制信息、配置备节点复制并启动复制进程。最后,通过`SHOW SLAVE STATUS\G;`监控复制状态,确保数据同步正常。此方法可提升数据的可靠性和可用性,需考虑网络条件对性能的影响。
511 0
|
分布式计算 并行计算 数据处理
大规模数据处理的最佳实践:使用 Dask 进行高效并行计算
【8月更文第29天】在大数据时代,高效地处理大规模数据集是至关重要的。Python 社区提供了一些强大的工具来帮助开发者进行并行和分布式计算,其中之一就是 Dask。本文将详细介绍如何使用 Dask 来优化大规模数据集的处理效率,并提供一些实用的代码示例。
1907 3
完美解决Non-terminating decimal expansion; no exact representable decimal result.异常
完美解决Non-terminating decimal expansion; no exact representable decimal result.异常
26949 0
完美解决Non-terminating decimal expansion; no exact representable decimal result.异常
|
消息中间件 存储 缓存
RocketMQ发送消息原理(含事务消息)
本文深入探讨了RocketMQ发送消息的原理,包括生产者端的发送流程、Broker端接收和处理消息的流程,以及事务消息的特殊处理机制,提供了对RocketMQ消息发送机制全面的理解。
RocketMQ发送消息原理(含事务消息)
若依修改---白名单怎样添加,怎样在初始化页面初始为自己的页面
若依修改---白名单怎样添加,怎样在初始化页面初始为自己的页面
若依修改---白名单怎样添加,怎样在初始化页面初始为自己的页面
|
12月前
|
前端开发 Java API
Swagger接口文档 —— 手把手教学,全方位超详细小白能看懂,百分百能用Java版
本文提供了一份详细的Swagger接口文档生成工具的使用教程,包括了导入依赖、配置类设置、资源映射、拦截器配置、Swagger注解使用、生成接口文档、在线调试页面访问以及如何设置全局参数(如token),旨在帮助Java开发者快速上手Swagger。
6938 0
Swagger接口文档 —— 手把手教学,全方位超详细小白能看懂,百分百能用Java版
|
SQL 算法 Java
(二十六)MySQL分库篇:Sharding-Sphere分库分表框架的保姆级教学!
前面《MySQL主从原理篇》、《MySQL主从实践篇》两章中聊明白了MySQL主备读写分离、多主多写热备等方案,但如果这些高可用架构依旧无法满足业务规模,或业务增长的需要,此时就需要考虑选用分库分表架构。
5260 4
|
弹性计算 物联网 网络性能优化
MQTT常见问题之connection reset by peer 异常如何解决
MQTT(Message Queuing Telemetry Transport)是一个轻量级的、基于发布/订阅模式的消息协议,广泛用于物联网(IoT)中设备间的通信。以下是MQTT使用过程中可能遇到的一些常见问题及其答案的汇总: