禅与计算机 禅与计算机
首页
  • Java基础

    • 聊一聊java一些核心知识点
    • 聊聊java面向对象核心知识点
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于提示词工程的Redis签到功能开发实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 写作

    • 写好技术博客的5大核心原则:从认知科学到AI工具的全流程指南
  • 开发工具

    • IDEA配置详解与高效使用指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • 从Lucene到Elasticsearch:进化之路
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

sharkchili

计算机禅修者
首页
  • Java基础

    • 聊一聊java一些核心知识点
    • 聊聊java面向对象核心知识点
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于提示词工程的Redis签到功能开发实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 写作

    • 写好技术博客的5大核心原则:从认知科学到AI工具的全流程指南
  • 开发工具

    • IDEA配置详解与高效使用指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • 从Lucene到Elasticsearch:进化之路
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • 一文带你速通Go语言基础语法
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发的Go语言协程实践
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • 从开源框架中学习那些实用的位运算技巧
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java基础

  • 并发编程

  • JVM相关

  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 深入解读 Spring MVC:Web 开发的得力助手
    • 探索 Spring 事务的奥秘
    • 来聊聊事务监听
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 深入剖析源码速通Spring多数据源问题
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于sharding-jdbc拓展点实现复杂分库分表算法
      • 写在文章开头
      • 详解自定义分表逻辑开发
        • 基于复杂发表算法的案例说明
        • 基于源码了解拓展点
        • 配置与分表算法实现
        • 自定义分表算法演示
      • 详解Sharding-JDBC几种分片策略
        • Sharding-JDBC分片策略概览
        • 标准分片策略(范围分片)
        • 复杂分片策略
        • 强制路由策略
        • 行表达式分片算法
      • 小结
      • 参考
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
    • 一文快速掌握高性能内存队列Disruptor
    • 安利一个轻量级流程引擎compileflow
    • 来聊聊一个轻量级的有限状态机Cola-StateMachine
  • Java核心技术
  • 深入理解Spring框架
sharkchili
2024-05-21
目录

基于sharding-jdbc拓展点实现复杂分库分表算法

# 写在文章开头

我们之前介绍一款轻量级的分库分表中间件sharding-jdbc,默认情况下该框架的分表算法都是采用内联表达式进行配置,对于某些比较灵活的需求无法实现,所以本文就以一个基于电话号码号头的案例介绍一下如何通过基于sharding-jdbc拓展点实现复杂分库分表算法。

PS: 如果对于sharding-jdbc不了解的读者,可以移步笔者之前写的这两篇文章深入了解sharding-jdbc的使用和原理:

一文快速上手Sharding-JDBC:https://mp.weixin.qq.com/s?__biz=MzkwODYyNTM2MQ==&mid=2247484885&idx=1&sn=21a3a7bd55feba042f77c4b88804fd36&chksm=c0c6516bf7b1d87d5c1212c6c6d135e1bcac6a8b2034202a8a0785a064982a471d8361e0b9ee#rd (opens new window)

sharding-jdbc如何实现分页查询:https://mp.weixin.qq.com/s/20jdhjj20kcN61ICNn4GeQ (opens new window)

Hi,我是 sharkChili ,是个不断在硬核技术上作死的技术人,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili 。

同时也非常欢迎你star我的开源项目mini-redis:https://github.com/shark-ctrl/mini-redis (opens new window)

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

# 详解自定义分表逻辑开发

# 基于复杂发表算法的案例说明

我们的案例是为了采集不同地区的电话号码用户的信息,希望相同号头的电话号码会落到同一张分表上,例如我们现在有分表3张,有一个电话号码10658888,我们必须截取到1065和分表数进行取模运算得到分表名user_0:

# 基于源码了解拓展点

我们直接定位到框架进行分库分表计算的代码段StandardRoutingEngine的routeTables,可以看到该方法会通过程序初始化加载好的shardingRule定位到当前分表策略:

private Collection<DataNode> routeTables(final TableRule tableRule, final String routedDataSource, final List<RouteValue> tableShardingValues) {
		//获取分表的前缀,以本文为例就是user
        Collection<String> availableTargetTables = tableRule.getActualTableNames(routedDataSource);
        //基于shardingRule调用getTableShardingStrategy获取分表策略
        Collection<String> routedTables = new LinkedHashSet<>(tableShardingValues.isEmpty() ? availableTargetTables
                : shardingRule.getTableShardingStrategy(tableRule).doSharding(availableTargetTables, tableShardingValues));
        Preconditions.checkState(!routedTables.isEmpty(), "no table route info");
        Collection<DataNode> result = new LinkedList<>();
        for (String each : routedTables) {
            result.add(new DataNode(routedDataSource, each));
        }
        return result;
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14

查看getTableShardingStrategy方法可以看到,如果tableRule没有实现默认分表策略,则采用默认也就是我们配置的内敛策略defaultTableShardingStrategy ,反之返回我们自定义实现的分表策略:


 public ShardingStrategy getTableShardingStrategy(final TableRule tableRule) {
 		//若getTableShardingStrategy返回空说明我们没有自定义实现类,返回defaultTableShardingStrategy 通过内联表达式进行分表运算,反之返回我们的自定义实现类
        return null == tableRule.getTableShardingStrategy() ? defaultTableShardingStrategy : tableRule.getTableShardingStrategy();
    }

1
2
3
4
5
6

此时我们可以推测tableShardingStrategy的配置就决定了我们是走内联表达式还是自定义类分表算法,通过源码的定位笔者发现tableShardingStrategy关于分表的配置来源于配置,在程序启动时tableShardingStrategy会根据yml的配置得到分表前缀如果是.table-strategy.standard.则说明当前程序采用的是自定义分表算法,就会基于这段配置定位到Java类生分表引擎:

对应的我们给出分表算法初始化的入口:

public TableRule(final TableRuleConfiguration tableRuleConfig, final ShardingDataSourceNames shardingDataSourceNames, final String defaultGenerateKeyColumn) {
        //......
        //基于配置的值决定分表算法如何创建
        tableShardingStrategy = null == tableRuleConfig.getTableShardingStrategyConfig() ? null : ShardingStrategyFactory.newInstance(tableRuleConfig.getTableShardingStrategyConfig());
        //......
    }
1
2
3
4
5
6

继续步进我们就可以直接定位到对应分表配置加载逻辑

@Override
    public TableRuleConfiguration swap(final YamlTableRuleConfiguration yamlConfiguration) {
      //......
            
		//基于yml配置得到分表算法采用哪种方式            
		result.setTableShardingStrategyConfig(shardingStrategyConfigurationYamlSwapper.swap(yamlConfiguration.getTableStrategy()));
 
        //......
        return result;
    }
1
2
3
4
5
6
7
8
9
10

最终查看配置加载的swap就可以看到自定分表配置加载的逻辑可以看到,只要我们配置的是StandardShardingStrategyConfiguration前缀的配置,这段配置就会为我们生成自定义算法:

@Override
    public YamlShardingStrategyConfiguration swap(final ShardingStrategyConfiguration data) {
    //基于yml中给定的字段、分表类生成标准的分表策略配置
    StandardShardingStrategyConfiguration得到自定义分表算法
        YamlShardingStrategyConfiguration result = new YamlShardingStrategyConfiguration();
        if (data instanceof StandardShardingStrategyConfiguration) {
            result.setStandard(createYamlStandardShardingStrategyConfiguration((StandardShardingStrategyConfiguration) data));
        }
       //......
        return result;
    }
1
2
3
4
5
6
7
8
9
10
11

# 配置与分表算法实现

基于上述源码,笔者得到对应配置前缀,我们开始进行自定义分库分表算法的配置步骤,首先自然是完成数据源的配置,如下所示,笔者自定义分表数据源名称为ds0,后续数据源信息配置的datasource后面都要拼上这个自定义的数据源名称ds0:

# 数据源名称
spring.shardingsphere.datasource.names=ds0
# 数据源基本链接、账号、密码信息
spring.shardingsphere.datasource.ds0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds0.url=jdbc:mysql://localhost:3306/db?characterEncoding=utf-8
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456
1
2
3
4
5
6
7
8

完成数据源基本配置后就到最重要分表核心配置了,对应选项含义分别是:

  1. actual-data-nodes:配置分库分表的库表区间,以笔者为例,配置为单库多表,对应的配置为ds0.user_$->{0..2},即ds0这个数据源下的user_0、user_1、user_2。
  2. precise-algorithm-class-name:指定分库分表的策略的实现类的全路径,以笔者为例包的全路径为com.sharkChili.algorithm.TableShardingAlgorithm。
  3. sharding-column:配置分片键,本文采用的是用户表的电话号码也就是phone字段。
  4. key-generator.column:该表的主键id为id。
  5. key-generator.type:id算法采用雪花算法。

# 配置分表区间
spring.shardingsphere.sharding.tables.user.actual-data-nodes=ds0.user_$->{0..2}
# 指定自定义分表类的包全路径
spring.shardingsphere.sharding.tables.user.table-strategy.standard.precise-algorithm-class-name=com.sharkChili.algorithm.TableShardingAlgorithm
# 配置分表分片键
spring.shardingsphere.sharding.tables.user.table-strategy.standard.sharding-column=phone
# 配置主键生成策略,指定数据表的主键为id字典,id算法采用雪花算法
spring.shardingsphere.sharding.tables.user.key-generator.column=id
# id使用雪花算法,因为雪花算法生成的id具有全球唯一性,并且又有自增特性,适合mysql的innodb引擎
spring.shardingsphere.sharding.tables.user.key-generator.type=SNOWFLAKE
1
2
3
4
5
6
7
8
9
10
11

如果我们希望打印分库分表执行SQL日志可以加上这条配置:

# 打开sql输出日志
spring.shardingsphere.props.sql.show=true
1
2

最后我们给出分表实现类,直接继承PreciseShardingAlgorithm并执行泛型为phone字典的类型String,通过截取电话号码头4位通过取模算法返回分表名称:

@Slf4j
public class TableShardingAlgorithm implements PreciseShardingAlgorithm<String> {


    @Override
    public String doSharding(Collection<String> collection, PreciseShardingValue<String> phoneNum) {
        log.info("分表信息:{}", JSONUtil.toJsonStr(collection));

        //号头小于4位,放到默认表
        if (StrUtil.isEmpty(phoneNum.getValue()) || phoneNum.getValue().length() < 4) {
            return "user";
        }
        //获取号头进行取模获取表号
        String phonePrex = phoneNum.getValue().substring(0, 4);
        int tableNo = (Integer.valueOf(phonePrex)) % collection.size();
        log.info("preciseShardingValue:{} table no:{}", phoneNum, tableNo);
        //返回分表名
        return "user_" + tableNo;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 自定义分表算法演示

最后我们给出插入的测试代码:

@Test
    void insert() {

        User user = new User();
        user.setId((long) RandomUtil.randomInt());
        user.setName("user" + 7879879843L);
        user.setPhone("10658888");
        userMapper.insert(user);
    }
1
2
3
4
5
6
7
8
9

从日志可以看出,我们的插入数据定位到了分表0,与预期一致:

  INFO 11940 --- [           main] ShardingSphere-SQL                       : Actual SQL: ds0 ::: insert into user_0  (id, name, phone) VALUES (?, ?, ?) ::: [-1687644961, user7879879843, 10658888]
1

# 详解Sharding-JDBC几种分片策略

# Sharding-JDBC分片策略概览

上述代码我们已经通过inline关键字指明基于表达式user_$->{id % 3}所实现的内联策略,通过该配置与之关联的关系类YamlShardingStrategyConfiguration我们可以看出,Sharding-JDBC总共一共了如下几种分片策略:

  1. standard:精确分片策略,即基于用户给定的单个分片键定位对应的库表。
  2. complex:复杂分片策略,即基于用户传入的多个字段定位对应的库表。
  3. hint:强制路由策略,比较少用,该策略用基于用户传参并结合路由策略实现类定位库表。
  4. inline:内联表达式,基于用户给定的分片键值和表达式获取对应的库表。
  5. none:无分片策略。

对应的我们给出YamlShardingStrategyConfiguration 的配置类印证这种说法:

@Getter
@Setter
public class YamlShardingStrategyConfiguration implements YamlConfiguration {
    
    private YamlStandardShardingStrategyConfiguration standard;
    
    private YamlComplexShardingStrategyConfiguration complex;
    
    private YamlHintShardingStrategyConfiguration hint;
    
    private YamlInlineShardingStrategyConfiguration inline;
    
    private YamlNoneShardingStrategyConfiguration none;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 标准分片策略(范围分片)

我们先来说说标准分片策略,也就是我们上文所实现的自定义分片算法,这里我们介绍另一种基于范围分片的策略实现,如下所示,可以看到我们分片键为user表的id之后,指明range-algorithm-class-name即范围分片查询算法的实现类为TableRangeShardingAlgorithm:

spring.shardingsphere.sharding.tables.user.table-strategy.standard.sharding-column=id

# 指明user表的范围分片算法类为TableRangeShardingAlgorithm
spring.shardingsphere.sharding.tables.user.table-strategy.standard.range-algorithm-class-name=com.sharkChili.algorithm.TableRangeShardingAlgorithm
1
2
3
4

对应我们也给出范围分片实现的算法实现类TableRangeShardingAlgorithm :

@Slf4j
public class TableRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Long> rangeShardingValue) {
        //记录分片键对应的分表
        Set<String> resTbSet = new ConcurrentHashSet<>();
        //获取id起始值
        long begin = rangeShardingValue.getValueRange().lowerEndpoint();
        //获取id结束值
        long end = rangeShardingValue.getValueRange().upperEndpoint();
        //基于这个id的范围取模定位分表名称写入set中
        LongStream.rangeClosed(begin, end).forEach(i -> resTbSet.add("user_" + i % 3));

        log.info("res tb set:{}", resTbSet);
        return resTbSet;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

这里我们给出测试代码:

        UserMapper userMapper = SpringUtil.getBean(UserMapper.class);
        UserExample userExample = new UserExample();
        //指明id为2、3对应算法%3后的分表为0、1
         userExample.createCriteria()
                .andIdBetween(2L, 3L);

        List<User> userList = userMapper.selectByExample(userExample);
        log.info("user list:{}", userList);
1
2
3
4
5
6
7
8

输出结果如下,可以看到定位到了0和3两个分表,与预期的逻辑一致:

需要补充的是范围分片和标准精准匹配的分片策略是兼容的,所以我们在标准分片的配置情况下可以同时实现两套算法针对不同维度的查询:

# 标准分片策略
spring.shardingsphere.sharding.tables.user.table-strategy.standard.sharding-column=id
# 标准分片的精准定位算法
spring.shardingsphere.sharding.tables.user.table-strategy.standard.precise-algorithm-class-name=com.sharkChili.algorithm.TableShardingAlgorithm
# 指明user表的范围分片算法类为TableRangeShardingAlgorithm
spring.shardingsphere.sharding.tables.user.table-strategy.standard.range-algorithm-class-name=com.sharkChili.algorithm.TableRangeShardingAlgorithm
1
2
3
4
5
6

# 复杂分片策略

涉及多字段条件的查询,sharding-jdbc同样提供了复杂分片策略配置,例如我们的分表查询算法的是基于id和age两个字段,那么我们就可以指明complex声明分片键为id和age,通过ComplexTableShardingAlgorithm实现分表逻辑:

# 指名复杂分片算法键为id和age
spring.shardingsphere.sharding.tables.user.table-strategy.complex.sharding-columns=id,age
# 复合分片算法
spring.shardingsphere.sharding.tables.user.table-strategy.complex.algorithm-class-name=com.sharkChili.algorithm.ComplexTableShardingAlgorithm
1
2
3
4

这里为了简单演示复杂分片算法的实现和使用,笔者简单的取出多值查询中id和age各一个,然后定位到分表集合,对应逻辑如下,读者可以参考注释了解一下逻辑,对应的我们查询时只需传入id和age后就会走到该算法,这里就不多做结果演示了:

public class ComplexTableShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> collection, ComplexKeysShardingValue<Long> complexKeysShardingValue) {
        Map<String, Collection<Long>> map = complexKeysShardingValue.getColumnNameAndShardingValuesMap();
        Collection<Long> idList = map.get("id");
        Collection<Long> ageList = map.get("age");
        Set<String> tbSet = new HashSet<>();
        //定位到age字段值
        long age = Long.valueOf(String.valueOf(ageList.stream().findFirst().get()));
        //定位到id字段值
        long id = idList.stream().findFirst().get();
        //如果年龄大于100则说明是无效数据,到user表查
        if (age > 100) {
            tbSet.add("user");
        } else {//反之基于id进行取模运算定位分表
            tbSet.add("user_" + id % 3);
        }
        return tbSet;

    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 强制路由策略

强制路由算是比较少用的分片策略,它的分表算法由用户自行实现且定位分表的逻辑与SQL语句没有任何关系,常用于系统维度的分表算法,所以配置时只需给出分表实现的策略类即可:

spring.shardingsphere.sharding.tables.user.table-strategy.hint.algorithm-class-name=com.sharkChili.algorithm.TableHintShardingAlgorithm
1

可以看到分表实现策略如下:

  1. 通过用户入参中获取逻辑分表
  2. 从入参出获取逻辑分表对应的value
  3. 基于上述两个值组装成分表
public class TableHintShardingAlgorithm implements HintShardingAlgorithm<String> {


    @Override
    public Collection<String> doSharding(Collection<String> tableNames, HintShardingValue<String> hintShardingValue) {
        //定位传入的逻辑分表
        String logicTableName = hintShardingValue.getLogicTableName();
        String logicTableValue = hintShardingValue.getValues().stream().findFirst().get();
        //基于values的第一个值定位分表号码,并于逻辑分配构成分表名称
        String tbName = logicTableName+"_"+logicTableValue;
        return Arrays.asList(tbName);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

hint算法是通过外部指定分片信息让分片策略决定路由最终指向,所以我们都是通过HintManager实例传入组装当前线程的逻辑表名和值从而定位到分表:

HintManager hintManager = HintManager.getInstance();

        try {
            //逻辑分表传入user,value传入0,让分表算法组成user_0
            hintManager.addTableShardingValue("user", 0L);
            List<User> userList = SpringUtil.getBean(UserMapper.class).selectByExample(null);
            log.info(JSONUtil.toJsonStr(userList));
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            //因为hintManager是基于threadLocal进行传值,所以用完后注意手动clear清除线程数据
            hintManager.clear();
        }
1
2
3
4
5
6
7
8
9
10
11
12
13

从输出结果就可以看出,我们通过传参实现参数驱动式的分片算法是成功的:

# 行表达式分片算法

最后还有一种行表达式的分片策略算法,只需给定id并在配置给定分片算法即可,使用于简单的分表算法的实现:

## 行表达式 使用哪一列用作计算分表策略,我们就使用id
spring.shardingsphere.sharding.tables.user.table-strategy.inline.sharding-column=id
##具体的分表路由策略,我们有3个user表,使用主键id取余3,余数0/1/2分表对应表user_0,user_2,user_2
spring.shardingsphere.sharding.tables.user.table-strategy.inline.algorithm-expression=user_$->{id % 3}
1
2
3
4

# 小结

本文结合源码实现了解到sharding-jdbc自定义分表算法实现的拓展点,并基于该拓展点完成我们的的号头分表逻辑,希望对你有所帮助。

我是 sharkchili ,CSDN Java 领域博客专家,mini-redis的作者,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili 。

同时也非常欢迎你star我的开源项目mini-redis:https://github.com/shark-ctrl/mini-redis (opens new window)

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

# 参考

SpringBoot集成ShardingSphere4.1.1(自定义分库、分表算法):https://zhuanlan.zhihu.com/p/414253622 (opens new window)

sharding-jdbc 分库分表的 4种分片策略,还蛮简单的:https://www.cnblogs.com/chengxy-nds/p/13919981.html (opens new window)

Sharding-JDBC强制路由案例实战:https://bbs.huaweicloud.com/blogs/407215 (opens new window)

编辑 (opens new window)
上次更新: 2026/03/26, 01:05:31
sharding-jdbc如何实现分页查询
基于DynamicDataSource整合分库分表框架Shardingsphere

← sharding-jdbc如何实现分页查询 基于DynamicDataSource整合分库分表框架Shardingsphere→

最近更新
01
基于EasyExcel实现高效导出
03-25
02
从开源框架中学习那些实用的位运算技巧
03-25
03
浅谈分布式架构设计思想和常见优化手段
03-25
更多文章>
Theme by Vdoing | Copyright © 2025-2026 Evan Xu | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×
×