背景
近期学习sharding-sphere,在网上找资料做实验,发现大部分都不全,对于预期结果没有足够的例子,大部分都是降了插入和查询操作。自己把例子抄了一遍,做了一遍实验,把实验结果记录了一下。代码就不贴了,需要的话留言。
数据准备
用docker作为测试数据库,使用如下的脚本来创建docker镜像.
#compose.yaml
#版本号
version: "3"
services:
#第一个实例
sharding_0:
image: mysql
restart: always
hostname: sharding_0
container_name: sharding_0
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: sharding
TZ: Asia/Shanghai
volumes:
- ./sharding_0/mysql/data:/var/lib/mysql
- ./sharding_0/mysql/log:/var/log/mysql
- ./init-script_0:/docker-entrypoint-initdb.d/
sharding_1:
image: mysql
restart: always
hostname: sharding_1
container_name: sharding_1
ports:
- 3316:3306
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: sharding
TZ: Asia/Shanghai
volumes:
- ./sharding_1/mysql/data:/var/lib/mysql
- ./sharding_1/mysql/log:/var/log/mysql
- ./init-script_1:/docker-entrypoint-initdb.d/
按照配置中的要求创建相关目录,使用docker-compose up -d
来启动容器,其中,init-script_0
和init-script_1
下面要事先放好如下的初始化脚本文件init.sql
,文件名随意。mysql官方镜像会使用/docker-entrypoint-initdb.d
下的sql来进行数据库初始化操作。
# init.sql
grant all PRIVILEGES on *.* to 'root'@'%' with grant option;
flush privileges;
use sharding;
CREATE TABLE `t_user_0` (
`id` BIGINT NOT NULL,
`user_id` BIGINT NOT NULL,
`user_name` varchar(128) NOT NULL,
`user_nicky` varchar(128) NOT NULL,
`user_mobile` varchar(32) NOT NULL,
`user_status` char(1) NOT NULL DEFAULT '0',
`user_level` char(2) NOT NULL DEFAULT '01',
`user_point` INT NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE INDEX `unq_user0_user_id` (`user_id` ASC) VISIBLE,
UNIQUE INDEX `unq_user0_user_name` (`user_name` ASC) VISIBLE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户信息表';
CREATE TABLE `t_user_1` (
`id` BIGINT NOT NULL,
`user_id` BIGINT NOT NULL,
`user_name` varchar(128) NOT NULL,
`user_nicky` varchar(128) NOT NULL,
`user_mobile` varchar(32) NOT NULL,
`user_status` char(1) NOT NULL DEFAULT '0',
`user_level` char(2) NOT NULL DEFAULT '01',
`user_point` INT NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE INDEX `unq_user1_user_id` (`user_id` ASC) VISIBLE,
UNIQUE INDEX `unq_user1_user_name` (`user_name` ASC) VISIBLE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户信息表';
CREATE TABLE `sharding`.`t_order_0` (
`id` BIGINT NOT NULL,
`order_id` BIGINT NOT NULL,
`order_user` BIGINT NOT NULL,
`order_amount` SMALLINT NOT NULL,
`order_address` VARCHAR(512) NOT NULL,
`order_mobile` VARCHAR(32) NOT NULL,
`order_memo` VARCHAR(256) NOT NULL,
`order_status` CHAR(2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `unq_order0_order_id` (`order_id` ASC) VISIBLE
);
CREATE TABLE `sharding`.`t_order_1` (
`id` BIGINT NOT NULL,
`order_id` BIGINT NOT NULL,
`order_user` BIGINT NOT NULL,
`order_amount` SMALLINT NOT NULL,
`order_address` VARCHAR(512) NOT NULL,
`order_mobile` VARCHAR(32) NOT NULL,
`order_memo` VARCHAR(256) NOT NULL,
`order_status` CHAR(2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `unq_order0_order_id` (`order_id` ASC) VISIBLE
);
CREATE TABLE `sharding`.`t_goods` (
`id` BIGINT NOT NULL,
`goods_id` BIGINT NOT NULL,
`goods_name` varchar(256) NOT NULL,
`goods_type` TINYINT NOT NULL,
`goods_price` SMALLINT NOT NULL,
`goods_desp` VARCHAR(32) NOT NULL,
`goods_tags` VARCHAR(256) NOT NULL,
`goods_picture` VARCHAR(256) NOT NULL,
`goods_status` CHAR(2) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `unq_goods_goods_id` (`goods_id` ASC) VISIBLE
);
试验
使用springboot、mybatis、sharding-jdbc作为主要的试验环境,其中最关键的分库分表配置如下所示:
#application.yml
server:
port: 8081
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.study.cn.entity
#配置数据源
spring:
main:
allow-bean-definition-overriding: true
shardingsphere:
datasource:
names: ds1,ds0 # 数据源名称
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/sharding?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3316/sharding?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
sharding:
default-data-source-name: ds0
default-database-strategy:
inline:
sharding-column: id
algorithm-expression: ds$->{id % 2}
#binding-tables: t_user
tables:
t_user:
actual-data-nodes: ds$->{0..1}.t_user_$->{0..1}
table-strategy:
inline:
sharding-column: user_id
algorithm-expression: t_user_$->{user_id % 2}
key-generator:
column: id
type: SNOWFLAKE
props:
worker:
id: 10
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
table-strategy:
inline:
sharding-column: order_id
algorithm-expression: t_order_$->{order_id % 2}
key-generator:
column: id
type: SNOWFLAKE
props:
worker:
id: 20
t_goods:
actual-data-nodes: ds$->{0..1}.t_goods
database-strategy:
inline:
sharding-column: id
algorithm-expression: ds$->{id % 2}
key-generator:
column: id
type: SNOWFLAKE
props:
worker:
# id: 30
props:
sql:
show: true
整体参考了shardingsphere的官方例子:https://github.com/apache/shardingsphere-example
这种模式下,sharding-jdbc就像一个增强版的JDBC,应用程序操作逻辑表,t_user,t_order,t_goods,转换到实际的数据库操作时,sharding-jdbc会转换为具体的数据库操作,可能是ds0.t_user_0,ds1.t_user_1等等,完成了实际的分库分表。有几点需要注意:
查询模式下,查询结果是几个查询结果的并集;
如果要精确查询,分库和分表的字段都要在sql的where条件下,根据两个条件确定
actual-data-node
,然后发起查询;更新模式下,和查询类似,如果条件中没有包含所有的分库分表条件,则会根据实际条件情况分别执行。比如如果没有指定分库条件,则会在两个ds上执行,如果指定了分表条件,则在每个ds中路由到具体的分表执行;
这种模式下,使用jpa则问题多多,jpa的save方法,默认使用id作为条件,会提示“分表字段不能更新“之类的错误,使用mybatis精准控制sql更加方便。
当然,jpa可能有高级用法,目前还没有学习到。




