Java充电社
专辑
博文
联系我
本人继续续收门徒,亲手指导
分库分表ShardingSphere
-> 最新版 5.X 详解
1、前言 & git地址
2、关于版本
3、4.X 版本文档
4、纯java api案例
5、分片问题?
6、分片介绍
7、5种分片策略:场景&案例详解
8、广播表
9、表关联
10、读写分离+分片
11、yml方式
12、集成SpringBoot
13、最新版 5.X 详解
上一篇:集成SpringBoot
<div style="display:none"></div> # 1、背景 前面12篇都是围绕版本4进行介绍的。 2022.8月,ShardingSphere当前最新版本是 5.1.2,相对于版本4变化挺大的,代码基本重构了,扩展了很多新功能,整个系统的扩展性更强了,不过核心原理没有变,所以还是建议先看下前面12篇,然后再看本文,这样会更轻松。 如果直接去看官方文档,快速上手还是有点难度的,所以有了这篇文章,本文基于 5.1.2 版,通过案例介绍其用法,引导大家如何使用,顺便会介绍如何去学习其他功能的用法。 # 2、5.1.2版git地址 <a target="_blank" href="https://github.com/apache/shardingsphere/tree/5.1.2">https://github.com/apache/shardingsphere/tree/5.1.2</a> # 3、官方文档 git首页有文档入口,如下,强烈建议阅读:<a target="_blank" href="https://shardingsphere.apache.org/document/current/cn/overview/">点击直达</a> ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/417/44c521ae-ebe1-4efd-8c1b-dae5d3af2a65.png) ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/417/729326b4-e3f3-4c27-877d-e4586f8b42dc.png) # 4、案例 ## 1)需求 ds_shardingsphere5 库中有2个用户表:t_user_0,t_user_1,表中有2个字段(id:用户编号,name:姓名) 这2个表的分片规则: - t_user_0:存放id为偶数的用户数据 - t_user_1:存放id为奇数的用户数据 下面来看具体实现 ## 2)执行sql脚本 ```sql drop database if exists ds_shardingsphere5; create database ds_shardingsphere5; use ds_shardingsphere5; drop table if exists t_user_0; create table t_user_0( id bigint not null primary key, name varchar(128) not null ); drop table if exists t_user_1; create table t_user_1( id bigint not null primary key, name varchar(128) not null ); ``` ## 3)项目中引入maven配置 ```xml <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-jdbc-core</artifactId> <version>5.1.2</version> </dependency> ``` ## 4)创建测试类 代码如下,有些地方可能大家看不懂,不过没关系,稍后会介绍。 ```java public class Test1 { static DataSource dataSource; //@BeforeAll 标注的方法会在 @Test 标注的方法被执行前执行一次 @BeforeAll public static void init() throws SQLException { /** * 1、创建datasource */ Map<String, DataSource> dataSourceMap = createDataSources(); /** * 2、构建具体规则 */ Collection<RuleConfiguration> ruleConfigs = new ArrayList<>(); /** * 2.1、创建分片规则 */ ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration(); //2.2、创建t_user表的分片规则 ShardingTableRuleConfiguration userShardingTableRuleConfiguration = new ShardingTableRuleConfiguration("t_user", //逻辑表 "ds1.t_user_$->{0..1}"); //实际数据节点 //2.3、配置t_user的分表规则,分片字段是:user_id,分片算法是:userShardingAlgorithm(这个算法名称是自定义的,后面会定义这个名称对应的具体算法) userShardingTableRuleConfiguration.setTableShardingStrategy( new StandardShardingStrategyConfiguration( "id", "userShardingAlgorithm")); //2.4、将t_user表的分片规则加入到shardingRuleConfiguration中 shardingRuleConfiguration.getTables().add(userShardingTableRuleConfiguration); //2.5、定义分片 Properties userShardingAlgorithmProperties = new Properties(); userShardingAlgorithmProperties.put( "algorithm-expression", "t_user_$->{id%2}" ); ShardingSphereAlgorithmConfiguration userShardingAlgorithm = new ShardingSphereAlgorithmConfiguration("INLINE", userShardingAlgorithmProperties); //2.6、将定义好的 userShardingAlgorithm 算法加入到算法列表中(算法名称->算法) shardingRuleConfiguration.getShardingAlgorithms(). put("userShardingAlgorithm", userShardingAlgorithm); //2.7、将分片规则加入规则列表 ruleConfigs.add(shardingRuleConfiguration); /** * 3、建属性配置 */ Properties props = new Properties(); props.put(ConfigurationPropertyKey.SQL_SHOW.getKey(), "true"); /** * 4、创建数据源 */ dataSource = ShardingSphereDataSourceFactory.createDataSource( "shardingsphere-demo-db", null, dataSourceMap, ruleConfigs, props); } private static Map<String, DataSource> createDataSources() { Map<String, DataSource> dataSourceMap = new HashMap<>(); // 配置第 1 个数据源 HikariDataSource dataSource1 = new HikariDataSource(); dataSource1.setDriverClassName("com.mysql.jdbc.Driver"); dataSource1.setJdbcUrl("jdbc:mysql://localhost:3306/ds_shardingsphere5?characterEncoding=UTF-8"); dataSource1.setUsername("root"); dataSource1.setPassword("root123"); dataSourceMap.put("ds1", dataSource1); return dataSourceMap; } } ``` 下面上测试案例,所有测试案例对应的方法都放到上面这个测试类中。 ## 5)测试:插入 > 执行下面测试方法之前,先执行下上面的的sql脚本,清理下数据。 > > 下面代码将插入2条数据,按照路由规则,会被路由到不同的用户表,这些信息都会包含在运行结果中,注意看运行结果 ```java @Test public void m1() throws Exception { String sql = "insert into t_user values (?,?),(?,?)"; try (Connection connection = dataSource.getConnection();) { connection.setAutoCommit(false); PreparedStatement ps = connection.prepareStatement(sql); int parameterIndex = 1; ps.setInt(parameterIndex++, 1); ps.setString(parameterIndex++, "user-1"); ps.setInt(parameterIndex++, 2); ps.setString(parameterIndex++, "user-2"); ps.executeUpdate(); connection.commit(); } } ``` 运行输出,如下,id为1的被路由到了t_user_1中,id为2的被路由到了t_user_0中 ```sql Logic SQL: insert into t_user values (?,?),(?,?) Actual SQL: ds1 ::: insert into t_user_1 values (?, ?) ::: [1, user-1] Actual SQL: ds1 ::: insert into t_user_0 values (?, ?) ::: [2, user-2] ``` ## 6)测试:查询id为1的用户 ```java @Test public void m2() throws Exception { String sql = "select id,name from t_user where id = 1"; try (Connection connection = dataSource.getConnection(); PreparedStatement ps = connection.prepareStatement(sql);) { ResultSet rs = ps.executeQuery(); while (rs.next()) { long id = rs.getLong("id"); String name = rs.getString("name"); System.out.println(String.format("id:%s, name:%s", id, name)); } } } ``` 运行输出,如下,id为1的被路由到了t_user_1表 ```sql Logic SQL: select id,name from t_user where id = 1 Actual SQL: ds1 ::: select id,name from t_user_1 where id = 1 id:1, name:user-1 ``` # 5、案例完整代码 ```html https://gitee.com/javacode2018/shardingsphere5-demo ``` # 6、案例重点代码解释 ## 6.1、init方法 大家估计对案例中的init()方法有很多疑问,这里把代码再贴出来,如下 ```java @BeforeAll public static void init() throws SQLException { /** * 1、创建datasource */ Map<String, DataSource> dataSourceMap = createDataSources(); /** * 2、构建具体规则 */ Collection<RuleConfiguration> ruleConfigs = new ArrayList<>(); /** * 2.1、创建分片规则 */ ShardingRuleConfiguration shardingRuleConfiguration = new ShardingRuleConfiguration(); //2.2、创建t_user表的分片规则 ShardingTableRuleConfiguration userShardingTableRuleConfiguration = new ShardingTableRuleConfiguration("t_user", //逻辑表 "ds1.t_user_$->{0..1}"); //实际数据节点 //2.3、配置t_user的分表规则,分片字段是:user_id,分片算法是:userShardingAlgorithm(这个算法名称是自定义的,后面会定义这个名称对应的具体算法) userShardingTableRuleConfiguration.setTableShardingStrategy( new StandardShardingStrategyConfiguration( "id", "userShardingAlgorithm")); //2.4、将t_user表的分片规则加入到shardingRuleConfiguration中 shardingRuleConfiguration.getTables().add(userShardingTableRuleConfiguration); //2.5、定义分片 Properties userShardingAlgorithmProperties = new Properties(); userShardingAlgorithmProperties.put( "algorithm-expression", "t_user_$->{id%2}" ); ShardingSphereAlgorithmConfiguration userShardingAlgorithm = new ShardingSphereAlgorithmConfiguration("INLINE", userShardingAlgorithmProperties); //2.6、将定义好的 userShardingAlgorithm 算法加入到算法列表中(算法名称->算法) shardingRuleConfiguration.getShardingAlgorithms(). put("userShardingAlgorithm", userShardingAlgorithm); //2.7、将分片规则加入规则列表 ruleConfigs.add(shardingRuleConfiguration); /** * 3、建属性配置 */ Properties props = new Properties(); props.put(ConfigurationPropertyKey.SQL_SHOW.getKey(), "true"); /** * 4、创建数据源 */ dataSource = ShardingSphereDataSourceFactory.createDataSource( "shardingsphere-demo-db", null, dataSourceMap, ruleConfigs, props); } ``` ## 6.2、通过分片算法名称关联分片算法 > 如下,配置用户表分片规则的时候,指定的算法名称为`userShardingAlgorithm`,这个名称可以随便定义,但是这个名称对应的具体算法需要在箭头指向的位置定义。 ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/417/6634e2a0-e3dd-4bf8-ad34-f98f807b44e8.png) ## 6.3、定义具体的分片算法 如下图,红框中用于定义用户表具体的分表算法 ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/417/0909733a-3fe9-4a9b-9562-e1566d28302d.png) ### 1)问题1:上图中具体用的是什么算法呢? 用的是org.apache.shardingsphere.sharding.algorithm.sharding.inline.InlineShardingAlgorithm这个算法类 ### 2)问题2:红圈中的 INLINE 字符串是什么意思? INLINE 并不是乱写的,系统会通过INLINE找到其对应的算法类,即InlineShardingAlgorithm这算法。 ### 3)问题3:系统是如何通过INLINE找到InlineShardingAlgorithm的? 通过SPI机制找到的,SPI简单来说:通过SPI提供的方法,可以在程序中找到某个接口的所有实现类,并且会将这些实现类都进行实例化,返回返回给调用者。 SPI工作机制: - 1、调用者给spi传入一个接口 - 2、SPI会在当前项目中以及所有的jar中找`/META-INF/services/接口完整名称`这些文件,这些文件中定义了这个接口具体的实现类列表。 - 3、读取这些文件,得到实现类列表,然后通过反射将这些类实例化,返回给调用者 ### 4)问题4:INLINE 这个名称是在哪里定义的呢? 这要说一下shardingsphere中的spi机制了,shardingsphere中有个spi接口:`org.apache.shardingsphere.spi.type.typed.TypedSPI`,源码如下 ```java public interface TypedSPI { /** * Get type. * * @return type */ default String getType() { return ""; } /** * Get type aliases. * * @return type aliases */ default Collection<String> getTypeAliases() { return Collections.emptyList(); } } ``` shardingsphere所有需要使用SPI功能的接口都必须继承上面这个接口,实现类需要实现2个方法了,而使用方可以通过type或者aliases(别名)找到具体的实现类了。 `INLINE`对应`org.apache.shardingsphere.sharding.algorithm.sharding.inline.InlineShardingAlgorithm`类,这个类实现了`TypedSPI`接口,uml图如下 ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/417/0f5eed0a-b488-4ebe-b8d6-714fe633e127.png) 其type方法如下,清晰了吧 ```java @Override public String getType() { return "INLINE"; } ``` 上面的UML图中还可以看出:InlineShardingAlgorithm 还实现了ShardingAlgorithm 接口,而InlineShardingAlgorithm接口对应的spi文件在`shardingsphere-sharding-core-5.1.2.jar/META/service/org.apache.shardingsphere.sharding.spi.ShardingAlgorithm`中,如下:这里面列出了shardingsphere为我们提供的所有常见的算法,建议都看一遍 ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/417/b1b9b689-c6dd-4dd1-b96b-5c41ec34bc29.png) 到这里大家都明了了。 若要使用其他算法,只需去看`org.apache.shardingsphere.sharding.spi.ShardingAlgorithm`接口实现类,以及其type方法返回值,就可以了,通过type的值便引用到具体的算法,大家自行发挥。 ### 5)问题5:SPI得到的实例对象的属性如何设置? 通过spi创建出来的对象,他们内部有很多属性,这些属性的值如何设置呢? 比如INLINE对应的InlineShardingAlgorithm类,源码如下,其内部有2个属性需要设置,这2个属性是根据init方法传入的Properties来设置的,外部需要传入一个Properteis对象,这个在哪定义的呢?继续向下看 ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/417/ad903aa1-a8d4-49a0-8f09-be2007dd915a.png) algorithmExpression属性是通过`getAlgorithmExpression(props)`实现的,源码如下 ```java private static final String ALGORITHM_EXPRESSION_KEY = "algorithm-expression"; private String getAlgorithmExpression(final Properties props) { String expression = props.getProperty(ALGORITHM_EXPRESSION_KEY); Preconditions.checkState(null != expression && !expression.isEmpty(), "Inline sharding algorithm expression cannot be null or empty."); return InlineExpressionParser.handlePlaceHolder(expression.trim()); } ``` 重点在`props.getProperty(ALGORITHM_EXPRESSION_KEY)`这行,而ALGORITHM_EXPRESSION_KEY是个常量,其值是algorithm-expression,最终algorithmExpression的值来源于props.getProperty(“algorithm-expression”),这部分信息和测试案例中的代码遥相呼应,如下,红框中的内容就是用来定义InlineShardingAlgorithm类中属性的值的,一目了然了吧。 ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/417/7c7d9a45-60ad-419f-ac3c-acc31f0d42e0.png) shardingsphere中spi扩展的类,其属的值都是通过Properties来指定的。 # 7、学习建议 本文通过一个简单案例介绍了版本5中shardingsphere的用法,以及一些原理,看懂本文之后,再结合官方文档,上手其他功能就很快了。 学习建议: 1、首先一定要去看官方文档,最好通读一遍 2、将git上代码拉下来看案例 3、不要要看,一定要多实战 4、多看看源码,学习其优良的设计 <a style="display:none" target="_blank" href="https://mp.weixin.qq.com/s/_S1DD2JADnXvpexxaBwLLg" style="color:red; font-size:20px; font-weight:bold">继续收门徒,亲手带,月薪 4W 以下的可以来找我</a> ## 最新资料 1. <a href="https://mp.weixin.qq.com/s?__biz=MzkzOTI3Nzc0Mg==&mid=2247484964&idx=2&sn=c81bce2f26015ee0f9632ddc6c67df03&scene=21#wechat_redirect" target="_blank">尚硅谷 Java 学科全套教程(总 207.77GB)</a> 2. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484192&idx=1&sn=505f2faaa4cc911f553850667749bcbb&scene=21#wechat_redirect" target="_blank">2021 最新版 Java 微服务学习线路图 + 视频</a> 3. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484573&idx=1&sn=7f3d83892186c16c57bc0b99f03f1ffd&scene=21#wechat_redirect" target="_blank">阿里技术大佬整理的《Spring 学习笔记.pdf》</a> 4. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247484544&idx=2&sn=c1dfe907cfaa5b9ae8e66fc247ccbe84&scene=21#wechat_redirect" target="_blank">阿里大佬的《MySQL 学习笔记高清.pdf》</a> 5. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247485167&idx=1&sn=48d75c8e93e748235a3547f34921dfb7&scene=21#wechat_redirect" target="_blank">2021 版 java 高并发常见面试题汇总.pdf</a> 6. <a href="https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247485664&idx=1&sn=435f9f515a8f881642820d7790ad20ce&scene=21#wechat_redirect" target="_blank">Idea 快捷键大全.pdf</a> ![](https://itsoku.oss-cn-hangzhou.aliyuncs.com/itsoku/blog/article/1/2883e86e-3eff-404a-8943-0066e5e2b454.png)
#custom-toc-container