ShardingSphere-JDBC入门使用
什么是ShardingSphere?
Apache ShardingSphere 是一款分布式的数据库生态系统, 可以将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。 它主要由ShardingSphere-JDBC和ShardingSphere-Proxy两个可独立使用、也可混合使用的产品组成。
什么是ShardingSphere-Proxy?
ShardingSphere-Proxy 定位为透明化的数据库代理端,通过实现数据库二进制协议,对异构语言提供支持。 目前提供 MySQL 和 PostgreSQL 协议,透明化数据库操作,对 DBA 更加友好。
- 向应用程序完全透明,可直接当做 MySQL/PostgreSQL 使用;
- 兼容 MariaDB 等基于 MySQL 协议的数据库,以及 openGauss 等基于 PostgreSQL 协议的数据库;
- 适用于任何兼容 MySQL/PostgreSQL 协议的的客户端,如:MySQL Command Client, MySQL Workbench, Navicat 等。

什么是ShardingSphere-JDBC?
ShardingSphere-JDBC 定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
- 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC;
- 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, HikariCP 等;
- 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,PostgreSQL,Oracle,SQLServer 以及任何可使用 JDBC 访问的数据库。

准备工作
创建Spring Boot项目,引入MySQL、ShardingSphere-JDBC等依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.1.2</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>创建若干张表,根据表创建controller、service、dao等代码
使用ShardingSphere-JDBC进行读写分离
数据库:master、slave;表:t_user
创建
application.properties作为基础配置文件1
2
3
4
5
6
7
8
9
10
11=9090
# 使用读写分离配置文件
=separate
=demo
=classpath*:**/sql/*.xml
# 打印sql日志
=true创建
application-separate.properties作为读写分离配置文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40# 数据源名称
=master,slave
# 数据源1(主数据源)
=com.alibaba.druid.pool.DruidDataSource
=com.mysql.cj.jdbc.Driver
=jdbc:mysql://host1:3306/practice?useUnicode=true&characterEncoding=utf-8&useSSL=false
=root
=password
# 数据源2(从数据源)
=com.alibaba.druid.pool.DruidDataSource
=com.mysql.cj.jdbc.Driver
=jdbc:mysql://host2:3306/practice?useUnicode=true&characterEncoding=utf-8&useSSL=false
=root
=password
# spring.shardingsphere.rules.readwrite-splitting.data-sources.<readwrite-splitting-data-source-name>.type=Static
# 读写分离类型,如: Static,Dynamic
=Static
# 写数据源名称
=master
# 读数据源名称,多个从数据源用逗号分隔
=slave
# 负载均衡算法名称
# 自定义轮询算法名称
=round_alg
# 自定义随机算法名称
#spring.shardingsphere.rules.readwrite-splitting.data-sources.my_ds.load-balancer-name=random_alg
# 自定义权重算法名称
#spring.shardingsphere.rules.readwrite-splitting.data-sources.my_ds.load-balancer-name=weight_alg
# spring.shardingsphere.rules.readwrite-splitting.load-balancers.<load-balance-algorithm-name>.type= # ????????
# 负载均衡算法类型
# 使用轮询算法
=ROUND_ROBIN
# 负载均衡算法属性配置
# 权重算法配置
#spring.shardingsphere.rules.readwrite-splitting.load-balancers.weight_alg.props.slave1=1
#spring.shardingsphere.rules.readwrite-splitting.load-balancers.weight_alg.props.slave2=2分别测试查询和插入接口,查看数据源是否正常路由
查询sql路由到从数据源

写入sql路由到主数据源

使用ShardingSphere-JDBC进行分库分表
数据库:ds_0、ds_1;表:t_order_0/1(ds_0/1)、t_order_item_0/1(ds_0/1)
创建
application.properties作为基础配置文件1
2
3
4
5
6
7
8
9
10=9090
=horizontal
=demo
=classpath*:**/sql/*.xml
# 打印sql日志
=true创建
application-horizontal.properties作为读写分离配置文件分库分表策略:
分库:订单表根据id对2取模,结果为0,路由到
ds_0数据库;结果为1,路由到ds_1数据库。订单明细表根据order_id对2取模,结果为0,路由到ds_0数据库;结果为1,路由到ds_1数据库,即和订单表保持一致分表:订单表、订单明细表根据
user_id对2取模,结果为0,路由到t_order_0、t_order_item_0;结果为1,路由到t_order_1、t_order_item_1表1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49# 数据源名称
=ds_0,ds_1
# 数据源1
=com.alibaba.druid.pool.DruidDataSource
=com.mysql.cj.jdbc.Driver
=jdbc:mysql://host1:3306/practice?useUnicode=true&characterEncoding=utf-8&useSSL=false
=root
=password
=com.alibaba.druid.pool.DruidDataSource
=com.mysql.cj.jdbc.Driver
=jdbc:mysql://host2:3306/practice?useUnicode=true&characterEncoding=utf-8&useSSL=false
=root
=password
# 数据节点,由数据源名 + 表名组成,以小数点分隔。多个表以逗号分隔,支持 inline 表达式。缺省表示使用已知数据源与逻辑表名称生成数据节点
=ds_$->{[0,1]}.t_order_$->{0..1}
=ds_$->{[0,1]}.t_order_item_$->{0..1}
# 分库策略
# 订单表根据id对2取模,路由到ds_0或ds_1数据库
=id
=alg_inline_id
# 订单明细表根据order_id对2取模,路由到ds_0或ds_1数据库,和订单表保持一致
=order_id
=alg_inline_order_id
# 分表策略
# 订单表根据user_id对2取模,路由到t_order_0或t_order_1表
=user_id
=alg_mod_id
# 订单明细表根据user_id对2取模,路由到t_order_item_0或t_order_item_1表
=user_id
=alg_mod_id
# 分片算法
# 订单表,行表达式分片算法
=INLINE
=ds_$->{id % 2}
# 订单表、订单明细表,取模分片算法
=MOD
=2
# 订单明细表,行表达式分片算法
=INLINE
=ds_$->{order_id % 2}
# 绑定表:分片规则一致的一组分片表。使用绑定表进行多表关联查询时,必须使用分片键进行关联,否则会出现笛卡尔积关联或跨库关联,从而影响查询效率
=t_order,t_order_item编写插入订单和订单行的代码,查看分库分表策略是否生效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public void mockInsert() {
OrderDO order1 = new OrderDO().setId(snowflake.nextId())
.setOrderNo(snowflake.nextIdStr())
.setUserId(202001L)
.setCreateTime("2023-08-12 17:35:11")
.setCreateTime("2023-08-12 17:35:11")
.setPayAmount(new BigDecimal("10889.0"));
OrderItemDO orderItem1 = new OrderItemDO().setId(snowflake.nextId())
.setOrderId(order1.getId())
.setUserId(202001L)
.setProductName("MacBook Pro")
.setAmount(new BigDecimal("10889.0"));
orderMapper.insert(order1);
orderItemService.insert(orderItem1);
OrderDO order2 = new OrderDO().setId(snowflake.nextId())
.setOrderNo(snowflake.nextIdStr())
.setUserId(202000L)
.setCreateTime("2023-08-12 17:41:54")
.setCreateTime("2023-08-12 17:41:54")
.setPayAmount(new BigDecimal("3899.0"));
OrderItemDO orderItem2 = new OrderItemDO()
.setId(snowflake.nextId())
.setOrderId(order2.getId())
.setUserId(202000L)
.setProductName("iWatch S8")
.setAmount(new BigDecimal("3899.0"));
orderMapper.insert(order2);
orderItemService.insert(orderItem2);
}查看分库分表情况
order_id为偶数、user_id为奇数
order_id为偶数、user_id为偶数
