1. 创建物理库
以root账号登录mariaDB, 创建三个schema: db_10001、db_10013、db_10020, 分别用来存放商户10001、10013、10020的数据; 然后在这三个schema上分别执行建表语句:
DROP TABLE if EXISTS tenant_user ;
CREATE TABLE tenant_user
(
id BIGINT UNSIGNED NOT NULL,
tenant_id INT(10) NOT NULL ,
name VARCHAR(255) NOT NULL ,
mbl_nbr VARCHAR(15) NOT NULL ,
idcard_no VARCHAR(15),
gender CHAR (1),
PRIMARY KEY(id)
) ;
DROP TABLE if EXISTS dict ;
CREATE TABLE dict
(
id BIGINT UNSIGNED NOT NULL,
kind VARCHAR(30) not null comment '类别',
kind_desc VARCHAR(45) comment '类别描述',
code VARCHAR(30) not null comment '编码',
name VARCHAR(250) not null comment '名称',
order_by SMALLINT not null comment '排序号',
status SMALLINT not null comment '0-作废 1-有效',
PRIMARY KEY (id)
);
注意, 对于需要水平切要的表,不能设置自增主键,否则不同结点会存在相同主键值; 另外,对于global类型的表,也不要用自增主键,并发时会造成主键冲突。
2. 配置逻辑库
按上图, 打开${MYCAT_HOME}/conf/schema.xml,创建逻辑库及相应的datanode:
<schema name="ftc-mycat" checkSQLschema="false" sqlMaxLimit="100">
<!-- 按字段tenant_id 切分的表 -->
<table name="tenant_user" rule="sharding-by-tenant" dataNode="dn_10001,dn_10013,dn_10020" />
<!-- global类型的表,其数据会复制到所有结点 -->
<table name="dict" primaryKey="id" type="global" dataNode="dn_10001,dn_10013,dn_10020" />
</schema>
<dataNode name="dn_10001" dataHost="localhost1" database="ftc_10001" />
<dataNode name="dn_10013" dataHost="localhost1" database="ftc_10013" />
<dataNode name="dn_10020" dataHost="localhost1" database="ftc_10020" />
打开${MYCAT_HOME}/conf/rule.xml,增加一项规则配置:
<tableRule name="sharding-by-tenant">
<rule>
<columns>tenant_id</columns>
<algorithm>by-tenant</algorithm>
</rule>
</tableRule>
...
<function name="by-tenant" class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">sharding-by-tenant.txt</property>
<property name="type">0</property>
<property name="defaultNode">0</property>
</function>
以下是新增文件sharding-by-tenant.txt的内容:
10001=0
10013=1
10020=2
打开${MYCAT_HOME}/conf/server.xml,给用户root授权逻辑库ftc_mycat的权限:
<user name="root">
<property name="password">123456</property>
<property name="schemas">TESTDB,ftc_mycat</property>
</user>
3. 读写测试
重启、并登录mycat:
C:\Users\HuQingmiao>mycat restart
wrapper | Stopping the Mycat-server service...
wrapper | Mycat-server stopped.
wrapper | Starting the Mycat-server service...
wrapper | Mycat-server started.
C:\Users\HuQingmiao>mysql -uroot -p123456 -hlocalhost -P8066 -Dftc_mycat
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB)
Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [ftc_mycat]>
写入数据, 执行以下脚本:
insert into tenant_user (id, tenant_id, name, mbl_nbr, idcard_no )
values (1, '10001', '牟森林', '13223232532', null);
insert into tenant_user (id, tenant_id, name, mbl_nbr, idcard_no )
values (2, '10013', '牟森林', '13223232532', null);
insert into tenant_user (id, tenant_id, name, mbl_nbr, idcard_no )
values (3, '10020', '胡三', '13520235368', null);
commit;
insert into dict (kind, kind_desc, code, name, order_by,status )
values ('tenant_entp_status', '企业信息状态', '1', '待认证', 1, 1);
insert into dict (kind, kind_desc, code, name, order_by,status )
values ('tenant_entp_status', '企业信息状态', '5', '已认证', 5, 1);
commit;
查看数据:
MySQL [ftc_mycat]> select * from dict;
+----+--------------------+--------------+------+----------+----------+--------+
| id | kind | kind_desc | code | name | order_by | status |
+----+--------------------+--------------+------+----------+----------+--------+
| 1 | tenant_entp_status | 企业信息状态 | 1 | 待认证 | 1 | 1 |
| 3 | tenant_entp_status | 企业信息状态 | 5 | 已认证 | 5 | 1 |
+----+--------------------+--------------+------+----------+----------+--------+
3 rows in set (0.00 sec)
MySQL [ftc_mycat]> select * from tenant_user;
+----+-----------+--------+-------------+-----------+--------+
| id | tenant_id | name | mbl_nbr | idcard_no | gender |
+----+-----------+--------+-------------+-----------+--------+
| 1 | 10001 | 牟森林 | 13223232532 | NULL | NULL |
| 2 | 10013 | 牟森林 | 13223232532 | NULL | NULL |
| 3 | 10020 | 胡三 | 13520235368 | NULL | NULL |
+----+-----------+--------+-------------+-----------+--------+
3 rows in set (0.00 sec)
4. 验证切分效果
现在登录本地mariaDB各个物理库,检查数据分布:
C:\Users\HuQingmiao>mysql -uroot -p123456
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 614
Server version: 10.1.16-MariaDB mariadb.org binary distribution
Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]> select * from ftc_10001.dict;
+----+--------------------+--------------+------+----------+----------+--------+
| id | kind | kind_desc | code | name | order_by | status |
+----+--------------------+--------------+------+----------+----------+--------+
| 1 | tenant_entp_status | 企业信息状态 | 1 | 待认证 | 1 | 1 |
| 2 | tenant_entp_status | 企业信息状态 | 2 | 认证失败 | 2 | 1 |
| 3 | tenant_entp_status | 企业信息状态 | 5 | 已认证 | 5 | 1 |
+----+--------------------+--------------+------+----------+----------+--------+
3 rows in set (0.00 sec)
MariaDB [(none)]> select * from ftc_10001.tenant_user;
+----+-----------+--------+-------------+-----------+--------+
| id | tenant_id | name | mbl_nbr | idcard_no | gender |
+----+-----------+--------+-------------+-----------+--------+
| 1 | 10001 | 牟森林 | 13223232532 | NULL | NULL |
+----+-----------+--------+-------------+-----------+--------+
1 row in set (0.00 sec)
由于上面dict表是global类型的, 因此在各个物理库上都有相同的3条记录。
5. 方案总结
这种按字段切分的方案, 要求租户的每个表(全局表除外)都要有tenant_id 列, 以供切分函数用; 因此本方案适合新开发的saas平台, 不适合把老系统升级为saas服务的情况,因为必须修改每条sql,为其添加tenant_id及相应值。