【ShardingSphere技术专题】「ShardingJDBC实战阶段」SpringBoot之整合ShardingJDBC实现分库分表(JavaConfig方式)

article/2025/9/13 9:05:42

前提介绍

ShardingSphere介绍

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

shardingJDBC使用的范围

  • 适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
  • 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。

详细一点的介绍直接看官网:https://shardingsphere.apache.org/document/current/cn/overview/

SQL语句相关

  • 逻辑表:水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例:订单数据根据主键尾数拆分为2张表,分别是t_order_0到t_order_1,他们的逻辑表名为t_order。

  • 真实表:在分片的数据库中真实存在的物理表。例:示例中的t_order_0到t_order_1

  • 数据节点:数据分片的最小单元。由数据源名称和数据表组成,例:ds_0.t_order_0;ds_0.t_order_1;

  • 绑定表:指分片规则一致的主表和子表。例如:t_order表和t_order_item表,均按照order_id分片,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大大提升。

  • 广播表:指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景。

数据分片相关

  • 分片键:用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段。

SQL中如果无分片字段,将执行全路由,性能较差。 除了对单分片字段的支持,ShardingSphere也支持根据多个字段进行分片。

  • 分片算法:通过分片算法将数据分片,支持通过=、>=、<=、>、<、BETWEEN和IN分片,分片算法需要应用方开发者自行实现,可实现的灵活度非常高。

目前提供4种分片算法

  • 精确分片算法:对应PreciseShardingAlgorithm,用于处理使用单一键作为分片键的=与IN进行分片的场景。需要配合StandardShardingStrategy使用。
  • 范围分片算法:对应RangeShardingAlgorithm,用于处理使用单一键作为分片键的BETWEEN AND、>、<、>=、<=进行分片的场景。需要配合StandardShardingStrategy使用。
  • 复合分片算法:对应ComplexKeysShardingAlgorithm,用于处理使用多键作为分片键进行分片的场景,包含多个分片键的逻辑较复杂,需要应用开发者自行处理其中的复杂度。需要配合ComplexShardingStrategy使用。
  • Hint分片算法:对应HintShardingAlgorithm,用于处理使用Hint行分片的场景。需要配合HintShardingStrategy使用。

分片策略:包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。

目前提供5种分片策略

  • 标准分片策略:对应StandardShardingStrategy,提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持。

    • StandardShardingStrategy只支持单分片键,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。
      • PreciseShardingAlgorithm是必选的,用于=和IN的分片
      • RangeShardingAlgorithm是可选的,用于BETWEEN AND, >, <, >=, <=分片,不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理。
  • 复合分片策略:对应ComplexShardingStrategy。提供对SQL语句中的=, >, <, >=, <=, IN和BETWEEN AND的分片操作支持

    • ComplexShardingStrategy支持多分片键,由于多分片键之间的关系复杂,因此并未进行过多的封装。
    • 而是直接将分片键值组合以及分片操作符透传至分片算法,完全由应用开发者实现,提供最大的灵活度。
  • 行表达式分片策略:对应InlineShardingStrategy。使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持,只支持单分片键。

  • 对于简单的分片算法,可以通过简单的配置使用,从而避免繁琐的Java代码开发,如: t_user_$->{u_id % 8} 表示t_user表根据u_id模8,而分成8张表,表名称为t_user_0到t_user_7。

  • Hint分片策略:对应HintShardingStrategy。通过Hint指定分片值而非从SQL中提取分片值的方式进行分片的策略。

  • 不分片策略:对应NoneShardingStrategy。

配置相关

分片规则:分片规则配置的总入口。包含数据源配置、表配置、绑定表配置以及读写分离配置等。

  • 数据源配置:真实数据源列表。
  • 表配置:逻辑表名称、数据节点与分表规则的配置
  • 数据节点配置:用于配置逻辑表与真实表的映射关系。
  • 分片策略配置:
    • 数据源分片策略:对应于DatabaseShardingStrategy。用于配置数据被分配的目标数据源。
    • 表分片策略:对应于TableShardingStrategy。用于配置数据被分配的目标表,该目标表存在与该数据的目标数据源内。故表分片策略是依赖与数据源分片策略的结果的。
  • 自增主键生成策略:通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。(雪花算法)

开发步骤

开发整合方式

方式一:基于配置文件集成,方便简单但是不够灵活

	<!--主要有以下依赖,分库分表策略直接在application.properties做相关配置即可--><dependency><groupId>io.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>3.1.0.M1</version></dependency><dependency><groupId>io.shardingsphere</groupId><artifactId>sharding-jdbc-spring-namespace</artifactId><version>3.1.0.M1</version></dependency>

方式二:这里我们主要基于java config的方式来集成到springboot中,更适合学习和理解

//相关依赖
<dependency><groupId>io.shardingsphere</groupId><artifactId>sharding-jdbc-core</artifactId><version>3.1.0</version>
</dependency>
<!--<dependency><groupId>io.shardingsphere</groupId><artifactId>sharding-transaction-2pc-xa</artifactId><version>3.1.0</version>
</dependency>-->
<dependency><groupId>io.shardingsphere</groupId><artifactId>sharding-jdbc-orchestration</artifactId><version>3.1.0</version>
</dependency>
<dependency><groupId>io.shardingsphere</groupId><artifactId>sharding-orchestration-reg-zookeeper-curator</artifactId><version>3.1.0</version>
</dependency>

定义相关配置类(DataSourceConfig => MybatisConfig => TransactionConfig)

ShardingSphereDataSourceConfig
import javax.sql.DataSource;
import java.lang.management.ManagementFactory;
import java.sql.SQLException;
import java.util.*;/*** @Author zhangboqing* @Date 2020/4/25*/
@Configuration
@Slf4j
public class ShardingSphereDataSourceConfig {@Bean("shardingDataSource")DataSource getShardingDataSource() throws SQLException {//初始化相关的分片规则配置信息控制机制ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();// 设置相关的数据源shardingRuleConfig.setDefaultDataSourceName("ds0");// 设置相关的Order表的相关的规则信息配置机制shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());// 设置相关的OrderItem表的相关的规则信息配置机制shardingRuleConfig.getTableRuleConfigs().add(getOrderItemTableRuleConfiguration());// 配置绑定表关系shardingRuleConfig.getBindingTableGroups().add("t_order, t_order_item");// 广播表操作机制shardingRuleConfig.getBroadcastTables().add("t_config");// 设置相关的分片机制策略(数据源分片策略机制控制)shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("user_id", "ds${user_id % 2}"));// 设置相关的分片策略机制,子啊inline模式下(包含了两种模式)shardingRuleConfig.setDefaultTableShardingStrategyConfig(getShardingStrategyConfiguration());// ShardingPropertiesConstant相关配置选项Properties properties = new Properties();//是否打印SQL解析和改写日志properties.put("sql.show",true);//用于SQL执行的工作线程数量,为零则表示无限制propertie.setProperty("executor.size","4");//每个物理数据库为每次查询分配的最大连接数量propertie.setProperty("max.connections.size.per.query","1");//是否在启动时检查分表元数据一致性propertie.setProperty("check.table.metadata.enabled","false");//用户自定义属性Map<String, Object> configMap = new HashMap<>();configMap.put("effect","分库分表");return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, properties);}// 配置相关的分片策略机制private ShardingStrategyConfiguration getShardingStrategyConfiguration(){// 精确匹配PreciseShardingAlgorithm<Long> preciseShardingAlgorithm = new PreciseShardingAlgorithm<Long>() {@Overridepublic String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {String prefix = shardingValue.getLogicTableName(); //逻辑表名称Long orderId = shardingValue.getValue(); //订单编码long index = orderId % 2; //订单表(分表路由索引)// t_order + "" + 0 = t_order0String tableName = prefix + "" +index;// 精确查询、更新之类的,可以返回不存在表,进而给前端抛出异常和警告。if (availableTargetNames.contains(tableName) == false) {LogUtils.error(log,"PreciseSharding","orderId:{},不存在对应的数据库表{}!", orderId, tableName);return availableTargetNames.iterator().next();}return tableName;
//                return availableTargetNames.iterator().next();}};// 范围匹配RangeShardingAlgorithm<Long> rangeShardingAlgorithm = new RangeShardingAlgorithm<Long>() {@Overridepublic Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {String prefix = shardingValue.getLogicTableName();Collection<String> resList = new ArrayList<>();// 获取相关的数据值范围Range<Long> valueRange = shardingValue.getValueRange();// 如果没有上限或者下限的没有,则直接返回所有的数据表if (!valueRange.hasLowerBound() || !valueRange.hasUpperBound()) {return availableTargetNames;}// 获取下限数据范围long lower = shardingValue.getValueRange().lowerEndpoint();BoundType lowerBoundType = shardingValue.getValueRange().lowerBoundType();// 获取下限数据范围long upper = shardingValue.getValueRange().upperEndpoint();BoundType upperBoundType = shardingValue.getValueRange().upperBoundType();// 下限数据信息值long startValue = lower;long endValue = upper;// 是否属于开区间(下限)if (lowerBoundType.equals(BoundType.OPEN)) {startValue++; //缩减范围1}// 是否属于开区间(上限)if (upperBoundType.equals(BoundType.OPEN)) {endValue--; // 缩减范围1}// 进行计算相关所需要是实体表for (long i = startValue; i <= endValue ; i++) {long index = i % 2;String res = prefix + "" +index;// 精确查询、更新之类的,可以返回不存在表,进而给前端抛出异常和警告。if (availableTargetNames.contains(res) == false) {LogUtils.error(log,"RangeSharding","orderId:{},不存在对应的数据库表{}!", i, res);}else{resList.add(res);}}if (resList.size() == 0) {LogUtils.error(log,"RangeSharding","无法获取对应表,因此将对全表进行查询!orderId范围为:{}到{}",startValue,endValue);return availableTargetNames;}return resList;}};// 设置相关整体的算法整合ShardingStrategyConfiguration strategyConf = new StandardShardingStrategyConfiguration("order_id", preciseShardingAlgorithm, rangeShardingAlgorithm);return strategyConf;}// 获取相关的Order订单规则表配置信息控制配置控制机制TableRuleConfiguration getOrderTableRuleConfiguration() {// 逻辑表 + 实际节点 :设置逻辑表与数据节点(数据分片的最小单位)的映射关系机制TableRuleConfiguration result = new TableRuleConfiguration("t_order", "ds${0..1}.t_order${0..1}");// 主键生成配置result.setKeyGeneratorConfig(getKeyGeneratorConfigurationForTOrder());return result;}//主键操作的生成策略private KeyGeneratorConfiguration getKeyGeneratorConfigurationForTOrder() {Properties keyGeneratorProp = getKeyGeneratorProperties();return new KeyGeneratorConfiguration("SNOWFLAKE", "order_id", keyGeneratorProp);}// 获取相关的Order订单规则表配置信息控制配置控制机制TableRuleConfiguration getOrderItemTableRuleConfiguration() {TableRuleConfiguration result = new TableRuleConfiguration("t_order_item", "ds${0..1}.t_order_item${0..1}");result.setKeyGeneratorConfig(getKeyGeneratorConfigurationForTOrderItem());return result;}// 创建相关keyOrderItem机制控制操作private KeyGeneratorConfiguration getKeyGeneratorConfigurationForTOrderItem() {Properties keyGeneratorProp = getKeyGeneratorProperties();return new KeyGeneratorConfiguration("SNOWFLAKE", "id", keyGeneratorProp);}// 生成键值相关的generator的配置信息控制private Properties getKeyGeneratorProperties() {Properties keyGeneratorProp = new Properties();String distributeProcessIdentify = NetUtils.getLocalAddress() + ":" + getProcessId();String workId = String.valueOf(convertString2Long(distributeProcessIdentify));keyGeneratorProp.setProperty("worker.id", workId);LogUtils.info(log, "shardingsphere init", "shardingsphere work id raw string is {}, work id is {}", distributeProcessIdentify, workId);return keyGeneratorProp;}// 数据源相关配置机制Map<String, DataSource> createDataSourceMap() {Map<String, DataSource> result = new HashMap<>();result.put("ds0", DataSourceUtils.createDataSource("ds0"));result.put("ds1", DataSourceUtils.createDataSource("ds1"));return result;}// 常见相关的workerid和dataid对应相关的进程idprivate String getProcessId(){String name = ManagementFactory.getRuntimeMXBean().getName();String pid = name.split("@")[0];return pid;}// 转换字符串成为相关的long类型private Long convertString2Long(String str){long hashCode = str.hashCode() + System.currentTimeMillis();if(hashCode < 0){hashCode = -hashCode;}return hashCode % (1L << 10);}
}
ShardingsphereMybatisConfig 配置机制
/*** @Author zhangboqing* @Date 2020/4/23*/
@Configuration
@MapperScan(basePackages = "com.zbq.springbootshardingjdbcjavaconfigdemo.dao",sqlSessionFactoryRef = "sqlSessionFactoryForShardingjdbc")
public class ShardingsphereMybatisConfig {@Autowired@Qualifier("shardingDataSource")private DataSource dataSource;@Bean("sqlSessionFactoryForShardingjdbc")public SqlSessionFactory sqlSessionFactoryForShardingjdbc() throws Exception {SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(dataSource);
//        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().
//                getResources("classpath*:**/*.xml"));sessionFactory.setTypeAliasesPackage("com.zbq.springbootshardingjdbcjavaconfigdemo.domain.entity");org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();configuration.setMapUnderscoreToCamelCase(true);sessionFactory.setConfiguration(configuration);return sessionFactory.getObject();}
}
ShardingsphereTransactionConfig 配置机制

主要定制化配置事务操作可以空战未来的,为了未来的查询扩展XA


@Configuration
@EnableTransactionManagement
public class ShardingsphereTransactionConfig {@Bean@Autowiredpublic PlatformTransactionManager shardingsphereTransactionManager(@Qualifier("shardingDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}

http://chatgpt.dhexx.cn/article/CB7WLJCO.shtml

相关文章

关东升给的ios学习路线图(可以借鉴)

来源&#xff1a; http://www.zhijieketang.com/classroom/3/introduction 首页 课程 免费课程 会员 关于我们 登录 注册 首页 iOS课程 iOS会员-iOS开发学习路线图 iOS会员-iOS开发学习路线图 扫二维码继续学习 (0评价) 价格&#xff1a; 1500 金币 学员(17) 课程(37) …

关东升的《从零开始学Swift》3月9日已经上架

大家一直期盼的《从零开始学Swift》于3月9日已经上架&#xff0c;它是关东升老师历时8个月的呕心沥血所编著&#xff0c;全书600多页&#xff0c;此本书基于Swift 2.x&#xff0c;通过大量案例全面介绍苹果平台的应用开发。全书共分5 部分&#xff0c;包括Swift语法篇、Cocoa T…

python从小白到大牛百度云盘_Java从小白到大牛 (关东升著) 中文pdf+mobi版[36MB]

《Java从小白到大牛》是一本Java语言学习立体教程&#xff0c;读者群是零基础小白&#xff0c;通过本书的学习能够成为Java大牛。主要内容包括&#xff1a;Java语法基础、Java编码规范、数据类型、运算符、控制语句、数组、字符串、面向对象基础、继承与多态、抽象类与接口、枚…

SpringBoot 整合 Sharding-JDBC

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、sharding-jdbc简介二、使用步骤 1.新建项目、引入依赖2.代码实战总结 前言 SpringBoot 整合 Sharding-JDBC 提示&#xff1a;以下是本篇文章正文内容&…

关东升的iOS实战系列图书 《iOS实战:传感器卷(Swift版)》已经上市

&#xfeff;&#xfeff; 承蒙广大读者的厚爱我的 《iOS实战&#xff1a;传感器卷&#xff08;Swift版&#xff09;》京东上市了&#xff0c;欢迎广大读者提出宝贵意见。http://item.jd.com/11760248.html 欢迎关注关东升新浪微博tony_关东升。 关注智捷课堂微信公共平台&…

Java从小白到大牛第1篇 Java基础-关东升-专题视频课程

Java从小白到大牛第1篇 Java基础—3042人已学习 课程介绍 本视频是智捷课堂推出的一套“Java语言学习立体教程”的视频第一部分&#xff0c;读者以及观看群是初级小白&#xff0c;通过本视频的学习能够成为Java大牛。本主要内容包括&#xff1a;Java语法基础、Java编码规范…

Sharding-JDBC 基础

Sharding-JDBC 是当当网开源的适用于微服务的分布式数据访问基础类库&#xff0c;完整的实现了分库分表&#xff0c;读写分离和分布式主键功能&#xff0c;并初步实现了柔性事务。 从 2016 年开源至今&#xff0c;在经历了整体架构的数次精炼以及稳定性打磨后&#xff0c;如今…

python从小白到大牛pdf 下载 资源共享_Kotlin从小白到大牛 (关东升著) 中文pdf高清版[12MB]...

本书是一本Kotlin语言学习立体教程&#xff0c;主要内容包括&#xff1a;Kotlin语法基础、Kotlin编码规范、数据类型、字符串、运算符、程序流程控制、函数、面向对象基础、继承与多态、抽象类与接口、高阶函数、Lambda表达式、数组、集合、函数式编程API、异常处理、线程、协程…

Java从小白到大牛第4篇项目实战1——PetStore宠物商店-关东升-专题视频课程

Java从小白到大牛第4篇项目实战1——PetStore宠物商店—1764人已学习 课程介绍 PetStore是Sun&#xff08;现在Oracle&#xff09;公司为了演示自己的Java EE技术&#xff0c;而编写的一个基于Web宠物店项目。PetStore是典型的电子商务项目&#xff0c;是现在很多电商平台的…

Sharding-JDBC(二)- Sharding-JDBC介绍

文章目录 一、Sharding-JDBC介绍1. Sharding-JDBC介绍2. Sharding-JDBC与JDBC性能对比 二、Sharding-JDBC快速入门1. 需求说明2. 环境搭建2.1 环境说明2.2 创建数据库2.3 引入maven依赖 3. 编写程序3.1 分片规则配置3.2.数据操作3.3.测试 4. 流程分析5. 其他集成方式5.1 Spring…

2022年适合初学者的Python书籍推荐

一、前言 网上有很多Python书或者视频&#xff0c;种类繁多该怎么选择&#xff1f; 看书全是文字看就了眼睛累&#xff0c;也容易厌倦&#xff0c;看视频有时候又觉得讲的慢&#xff0c;有其他方案吗&#xff1f; 其实&#xff0c;关于自学python&#xff0c;找一本浅显易懂&…

师傅带徒弟学:Python游戏开发引擎cocos2d-python-关东升-专题视频课程

师傅带徒弟学&#xff1a;Python游戏开发引擎cocos2d-python—299人已学习 课程介绍 Python语言之所以受欢迎&#xff0c;很大的原因是有很多可以使用的库&#xff0c;Python社区也有很多游戏开发库&#xff0c;其中较为优秀有&#xff1a;Cocos2d、Pyglet和Pygame&#xf…

关东升的《从零开始学Swift》即将出版

大家好&#xff1a; 苹果2015WWDC大会发布了Swift2.0&#xff0c;它较之前的版本Swift1.x有很大的变化&#xff0c;所以我即将出版《从零开始学Swift》《从零开始学Swift》将在《Swift开发指南》第1版的基础上添加Swift2.0的内容&#xff0c;同时摒弃第1版的一些不合理的内容&a…

最新出炉!《看漫画学Python 2》电子版火爆来袭,300页全新版PDF开放下载,零基础小白入门首选!

很多刚开始接触Python的朋友都会有一个共同的烦恼&#xff0c;自学好无聊&#xff0c;好枯燥&#xff0c;不想坚持了……所以秉持着让学Python好玩有趣的态度&#xff0c;给大家推荐一本最新出炉的“漫画书”《看漫画学Python 2》&#xff01; 图书简介&#xff1a;Python是一门…

关东升的《iOS实战:图形图像、动画和多媒体卷(Swift版)》上市了

关东升的《iOS实战&#xff1a;图形图像、动画和多媒体卷&#xff08;Swift版&#xff09;》上市了 承蒙广大读者的厚爱我的《iOS实战&#xff1a;图形图像、动画和多媒体卷&#xff08;Swift版&#xff09;》京东上市了&#xff0c;欢迎广大读者提出宝贵意见。。http://item.j…

关东升 IOS

51CTO博客大赛我的参赛主页http://blog.51cto.com/contest2013/701759期待您的一票&#xff01; 同时有好礼相送&#xff0c;欢迎学习iOS的小伙伴观看我的iOS入门免费系列课程如下&#xff1a; Objective C编程基础 &#xff08;24课时&#xff09; 只要4金币 iOS开发基础入门 …

Shell Date命令

shell Date命令 1、Date命令 date %Y 以四位数字格式打印年份 date %y 以二位数字格式打印年份 date %m 月份 date %d 日期 date %H 小时 date %M 分钟 date %S 秒 date %w 星期&#xff0c;如果结果显示0&#xff0c;则表示周日前一天的日期 date -d "-1 day" %d前…

Linux命令date命令

A.将日期转换为Unix时间戳 将当前时间以Unix时间戳表示&#xff1a; date %s 转换指定日期为Unix时间戳&#xff1a; date -d 2018-05-25 18:20 %s B.将Unix时间戳转换为日期时间 不指定日期时间的格式&#xff1a; date -d 1361542596 指定日期格式的转换&#xff1a; …

linux date输出时分秒,linux的date命令

date命令 在linux里面shell脚本打印时间。 date语法 date (选项)(参数)(date后面必须加空格)。 选项有下面几种 -d"字符串"&#xff1a;显示字符串所指定的时间&#xff1b; -s"字符串"&#xff1a;根据字符串设置时间&#xff1b; -u:显示GMT&#xff1b;…

Linux date命令

date命令是Linux中常用的一个命令&#xff0c;主要作用就是显示本机当前时间。如下&#xff1a; 在本人Linux操作系统中&#xff0c;date命令默认实现格式为年月日-星期-时分秒&#xff0c;然后是CST中央标准时间。不过&#xff0c;你也可以自行修改显示格式&#xff0c;如&…