在前面三期我们讲了有关ShardingSphere的东西:
标题 | 链接 |
---|---|
【实战篇】Docker安装MySQL集群 | juejin.cn/post/753828... |
ShardingSphere-JDBC入门教程(上篇) | juejin.cn/post/753981... |
ShardingSphere-JDBC入门教程(下篇) | juejin.cn/post/754455... |
那么这一期我们来讲一下ShardingSphere家族的ShardingSphere-Proxy,这篇文章将作为该系列的最后一篇文章。
我们再来回顾一下前面学习的ShardingSphere-JDBC是什么:

他是一个 Java 框架,可以不用安装任何东西直接在pom文件里面引入即可。我们再来看一下ShardingSphere-Proxy:

定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前提供 MySQL 和 PostgreSQL(兼容 openGauss 等基于 PostgreSQL 的数据库)版本,它可以使用任何兼容 MySQL/PostgreSQL 协议的访问客户端(如:MySQL Command Client, MySQL Workbench, Navicat 等)操作数据,对 DBA 更加友好。
- 向应用程序完全透明,可直接当做 MySQL/PostgreSQL 使用;
- 适用于任何兼容 MySQL/PostgreSQL 协议的的客户端。
在开发界中有一句话说的好:没有问题是封装一层解决不了的,如果有,那就再加一层。
他和我们之前学过的ShardingSphere-JDBC(以下简称jdbc)的区别就是ShardingSphere-Proxy(以下简称proxy) 是与程序是分离开来的,jdbc 则是在pom文件导入jar、写死在properties配置文件中的。而proxy则是在应用程序中什么都不用改,像正常连接mysql一样的连接proxy就好,大家可以把他认作就是一个mysql集群的代理数据库,我们只需要直接连接proxy,而剩下的操作都交给proxy去处理就好了。
安装proxy
这里我们使用docker进行安装,首先我们要准备一个mysql的驱动jar包:mysql的驱动下载
运行docker命令跑docker镜像:
diff
docker run -d
-v C:\docker\proxy\proxy-a\conf:/opt/shardingsphere-proxy/conf
-v C:\docker\proxy\proxy-a\ext-lib:/opt/shardingsphere-proxy/ext-lib
-e ES_JAVA_OPTS="-Xmx256m -Xms256m -Xmn128m"
-p 3321:3307
--name server-proxy-a
apache/shardingsphere-proxy:5.1.1

将下载下来的mysql驱动复制到C:\docker\proxy\proxy-a\ext-lib目录下面,因为我们要连接的是mysql所以需要这个驱动,而PostgreSQL则是不用驱动的。

我们在 C:\docker\proxy\proxy-a\conf
创建一个目录下面创建一个 server.yaml
文件,内容如下:
yaml
rules:
- !AUTHORITY
users:
- root@%:root
provider:
type: ALL_PRIVILEGES_PERMITTED
props:
sql-show: true
这里的作用是我们创建了一个拥有所有权限的root用户,密码也是root。下面那个就是显示sql。
之后重启容器就好了
shell
docker restart server-proxy-a
重启完成之后我们就可以和mysql一样去连接proxy了:

但是这个时候如果我们点击这个连接就会报错:

上面显示没我们没有配置数据源或者规则配置不对,因为他本身是一个中间件,没有存储数据的功能,所以我们需要配置使得proxy能连接上我们的mysql数据库
垂直分片
在上一期我们配置了jdbc的垂直分片:
在上篇文章中垂直分片的mysql环境已经被我们搭建好了,所有我们直接使用该mysql环境,我们同样在 C:\docker\proxy\proxy-a\conf
创建一个目录下面创建一个 config-sharding.yaml
文件,内容如下:
yaml
schemaName: sharding_db
dataSources:
ds_0:
url: jdbc:mysql://172.19.200.70:13306/d_user?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
ds_1:
url: jdbc:mysql://172.19.200.70:13307/d_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
rules:
- !SHARDING
tables:
t_user:
actualDataNodes: ds_0.t_user
t_order:
actualDataNodes: ds_1.t_order
可以看到这个里面的配置和我们之前的properties几乎一模一样,只不过位置从我们之前写在java程序的配置文件里面变为了写在proxy的配置文件里面了,对应用程序是无感的,但是这里有个小细节:ip不能和之前一样写127.0.0.1,要写本机的ip地址,如果知道容器的原理就很好懂了,因为要通过宿主机找其他容器的地址。
那么连接之后呢,我们发现没有报错了,多了一个叫做 sharding_db
的数据库,而这个数据库名字的由来就是我们在配置文件里面写的 schemaName
属性,我们点进去查看这个数据库,发现order表和user表赫然立在此处,这就是我们上次的数据表。

包括里面的数据都是存在的:

Java程序连接
其中程序我们还是用到了上一期文章里面的程序,唯二不同的是pom文件取消了 shardingsphere-jdbc-core-spring-boot-starter
jar包的导入

和配置文件取消了一系列复杂的配置,就和直接连接mysql是一模一样的:
properties
server.port=8083
#mysql数据库连接(proxy)
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3321/sharding_db?serverTimezone=GMT%2B8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
没了??对,应用程序就是这么干净,然后我们在测试一下是否可以成功:
properties
package com.masiyi.shardingsphere;
import com.masiyi.shardingsphere.entity.Order;
import com.masiyi.shardingsphere.entity.OrderItem;
import com.masiyi.shardingsphere.entity.User;
import com.masiyi.shardingsphere.mapper.OrderItemMapper;
import com.masiyi.shardingsphere.mapper.OrderMapper;
import com.masiyi.shardingsphere.mapper.UserMapper;
import com.masiyi.shardingsphere.vo.OrderVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.List;
@RestController
@RequestMapping
public class UserController {
@Autowired
private UserMapper userMapper;
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderItemMapper orderItemMapper;
/**
* 插入数据测试
*/
@PostMapping("insert/database")
public void testInsertOrderDatabaseStrategy(){
for (long i = 0; i < 4; i++) {
Order order = new Order();
order.setOrderNo("2025120488992");
order.setUserId(i + 1);
order.setAmount(new BigDecimal(100));
orderMapper.insert(order);
}
}
}
执行接口插入,查看数据库也是有数据的:

那么接下来我们就查看其他的两种配置
水平分片
没错,这个也是创建一个yaml文件,我们这次就叫 config-sharding-bindingTables.yaml
,这里我们名字要以 config-xxx开头
名字可以随便叫,因为proxy会读这个文件夹里面的 这两个文件 %SHARDINGSPHERE_PROXY_HOME%/conf/config-xxx.yaml
。 %SHARDINGSPHERE_PROXY_HOME%/conf/server.yaml
。
yaml
schemaName: sharding_db_1
dataSources:
d_user:
url: jdbc:mysql://172.19.200.70:13306/d_user?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
d_order0:
url: jdbc:mysql://172.19.200.70:13308/d_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
d_order1:
url: jdbc:mysql://172.19.200.70:13309/d_order?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
rules:
- !SHARDING
tables:
t_user:
actualDataNodes: d_user.t_user
t_order:
actualDataNodes: d_order${0..1}.t_order${0..1}
databaseStrategy:
standard:
shardingColumn: f_user_id
shardingAlgorithmName: alg_mod
tableStrategy:
standard:
shardingColumn: f_order_no
shardingAlgorithmName: alg_hash_mod
keyGenerateStrategy:
column: f_id
keyGeneratorName: snowflake
t_order_item:
actualDataNodes: d_order${0..1}.t_order_item${0..1}
databaseStrategy:
standard:
shardingColumn: f_user_id
shardingAlgorithmName: alg_mod
tableStrategy:
standard:
shardingColumn: f_order_no
shardingAlgorithmName: alg_hash_mod
keyGenerateStrategy:
column: f_id
keyGeneratorName: snowflake
bindingTables:
- t_order,t_order_item
shardingAlgorithms:
alg_inline_userid:
type: INLINE
props:
algorithm-expression: d_order$->{f_user_id % 2}
alg_mod:
type: MOD
props:
sharding-count: 2
alg_hash_mod:
type: HASH_MOD
props:
sharding-count: 2
keyGenerators:
snowflake:
type: SNOWFLAKE
那么配置之后呢,我们的proxy 里面就多了一个数据库 :sharding_db_1

配置文件改为连接改数据库之后写个接口测试一下:
java
/**
* 测试关联表插入
*/
@PostMapping("insert/orderAndOrderItem")
public void testInsertOrderAndOrderItem(){
for (long i = 1; i < 3; i++) {
Order order = new Order();
order.setOrderNo("wangfugui20250840" + i);
order.setUserId(1L);
orderMapper.insert(order);
for (long j = 1; j < 3; j++) {
OrderItem orderItem = new OrderItem();
orderItem.setOrderNo("wangfugui20250840" + i);
orderItem.setUserId(1L);
orderItem.setPrice(new BigDecimal(10));
orderItem.setCount(2);
orderItemMapper.insert(orderItem);
}
}
for (long i = 5; i < 7; i++) {
Order order = new Order();
order.setOrderNo("wangfugui20250840" + i);
order.setUserId(2L);
orderMapper.insert(order);
for (long j = 1; j < 3; j++) {
OrderItem orderItem = new OrderItem();
orderItem.setOrderNo("wangfugui20250840" + i);
orderItem.setUserId(2L);
orderItem.setPrice(new BigDecimal(1));
orderItem.setCount(3);
orderItemMapper.insert(orderItem);
}
}
}
可以看到数据成功插入:

读写分离
在 C:\docker\proxy\proxy-a\conf
创建一个目录下面创建一个 config-readwrite-splitting.yaml
文件,内容如下:
java
schemaName: readwrite_splitting_db
dataSources:
write_ds:
url: jdbc:mysql://${IP}:3306/db_user?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
read_ds_0:
url: jdbc:mysql://${IP}:3307/db_user?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
read_ds_1:
url: jdbc:mysql://${IP}:3308/db_user?serverTimezone=UTC&useSSL=false
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
rules:
- !READWRITE_SPLITTING
dataSources:
readwrite_ds:
type: Static
props:
write-data-source-name: write_ds
read-data-source-names: read_ds_0,read_ds_1
ok啊,这就是本期博客的全部内容,我们使用下来发现,我们通过proxy配置的数据库和数据表全都是一个:

但是我们得知道,这个表实际是对应的两个库里面的两个表:

是不是觉得proxy很厉害,对于程序来说也只是一个地址,对于用户来说也是透明的(例如Navicat也是一个表和一个库,你不用关心底层是如何实现如何存储的),作者在之前写文章的时候也考虑过MyCat,但是这个现在的资料实在太少了,社区也不如proxy活跃,所以最终选择了 ShardingSphere 的产品。
