需求
- 可绑定数据源;
- 通过配置文件指定。
建表语句:
create table cz_dept(id int auto_increment primary key , dept_no varchar(16) not null,dept_name varchar(32));
为演示mycat根据列值绑定数据源功能,以该表为例做演示,拆分键为dept_no
。
rule.xml
这个配置文件主要是进行规则信息的配置。
1.function标签:
<function name="hash-string"
class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-string.txt</property>
<property name="type">1</property>
</function>
首先这里制定了type
,0表示数字类型的拆分键,为1表示拆分键为字符串类型。
上面的配置定义了一个名为hash-string
的函数。
mapFile
指向partition-hash-string.txt,这个文件实际保存了规则映射信息:
cn31101=0
cn31103=0
cn31105=0
cn31102=1
cn31101,cn31103,cn31105保存到0号节点,
cn31102保存到1号节点。
2.tableRule标签:
<tableRule name="hash-string">
<rule>
<columns>dept_no</columns>
<algorithm>hash-string</algorithm>
</rule>
</tableRule>
此处指定拆分的列为dept_no
,指定拆分的函数为上面定义的hash-string
。
schema.xml
这个配置文件主要是定义逻辑库中的逻辑表的信息。
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" randomDataNode="dn1">
<!-- auto sharding by id (long) -->
<!--splitTableNames 启用<table name 属性使用逗号分割配置多个表,即多个表使用这个配置-->
<table name="cz_dept" primaryKey="id" autoIncrement="true" dataNode="dn1,dn2" rule="hash-string"/>
<table name="mycat_sequence" primaryKey="name" dataNode="dn1"/>
</schema>
<dataNode name="dn1" dataHost="localhost1" database="demo_1" />
<dataNode name="dn2" dataHost="localhost1" database="demo_2" />
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="192.168.133.15:3306" user="pcloud"
password="pcloud">
</writeHost>
</dataHost>
</mycat:schema>
我提前在mysql创建了两个数据库,名为demo_1
和demo_2
。
逻辑库中主要创建的逻辑表是cz_dept
,分布在dn1
节点和dn2
节点上,指向的拆分规则为hash-string。
注:在此处定义后,可连接到mycat执行sql语句建表。创建完以后到demo_1和demo_2数据库上面查看是否创建成功。
测试
根据上述配置文件的配置,cn31101、cn31103和cn31105会插入到0号节点,这里对应的也就是dn1节点;
cn31102会插入到dn2节点。
1.插入cn31101的数据
insert into cz_dept(dept_no,dept_name) values('cn31101','张三')
> Affected rows: 1
> 时间: 0.032s
手动连接到demo_1数据库进行查询:
select * from demo_1.cz_dept;
ID DEPT_NO DEPT_NAME
2 cn31101 张三
确定数据已经插入到dn1节点。
2.插入cn31102的数据
insert into cz_dept(dept_no,dept_name) values('cn31102','李四')
> Affected rows: 1
> 时间: 0.014s
手动连接到demo_2数据库进行查询:
select * from demo_2.cz_dept;
ID DEPT_NO DEPT_NAME
3 cn31102 李四
确定数据已经插入到dn2节点。
3.插入未维护的数据
这里插入cn38888的数据:
insert into cz_dept(dept_no,dept_name) values('cn38888','王二麻子')
> 1064 - can't find any valid datanode :CZ_DEPT -> DEPT_NO -> cn38888
> 时间: 0.012s
会提示没有该配置映射,插入失败。
注:这里可以将没有匹配的数据插入到默认节点,但根据医卫的场景,认为该场景不适合。如需要该配置可修改rule.xml
,新增defaultNode
配置:
<function name="hash-string"
class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-string.txt</property>
<property name="type">1</property>
<property name="defaultNode">0</property>
</function>
关于mycat全局序列
上述用例中用了主键自增的id,这个如果直接使用并不能保证在分布式数据库环境生效,需要使用全局序列。
这个信息维护在表中,需要到某个mysql节点执行建表和创建触发器的函数:
DROP TABLE IF EXISTS MYCAT_SEQUENCE;
CREATE TABLE MYCAT_SEQUENCE ( name VARCHAR(64) NOT NULL, current_value BIGINT(20) NOT NULL, increment INT NOT NULL DEFAULT 1, PRIMARY KEY (name) ) ENGINE=InnoDB;
-- ----------------------------
-- Function structure for `mycat_seq_currval`
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_currval`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_currval`(seq_name VARCHAR(64)) RETURNS varchar(64) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval="-1,0";
SELECT concat(CAST(current_value AS CHAR),",",CAST(increment AS CHAR) ) INTO retval FROM MYCAT_SEQUENCE WHERE name = seq_name;
RETURN retval ;
END
;;
DELIMITER ;
-- ----------------------------
-- Function structure for `mycat_seq_nextval`
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_nextval`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_nextval`(seq_name VARCHAR(64)) RETURNS varchar(64) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
DECLARE val BIGINT;
DECLARE inc INT;
DECLARE seq_lock INT;
set val = -1;
set inc = 0;
SET seq_lock = -1;
SELECT GET_LOCK(seq_name, 15) into seq_lock;
if seq_lock = 1 then
SELECT current_value + increment, increment INTO val, inc FROM MYCAT_SEQUENCE WHERE name = seq_name for update;
if val != -1 then
UPDATE MYCAT_SEQUENCE SET current_value = val WHERE name = seq_name;
end if;
SELECT RELEASE_LOCK(seq_name) into seq_lock;
end if;
SELECT concat(CAST((val - inc + 1) as CHAR),",",CAST(inc as CHAR)) INTO retval;
RETURN retval;
END
;;
DELIMITER ;
-- ----------------------------
-- Function structure for `mycat_seq_setvals`
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_nextvals`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_nextvals`(seq_name VARCHAR(64), count INT) RETURNS VARCHAR(64) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
DECLARE val BIGINT;
DECLARE seq_lock INT;
SET val = -1;
SET seq_lock = -1;
SELECT GET_LOCK(seq_name, 15) into seq_lock;
if seq_lock = 1 then
SELECT current_value + count INTO val FROM MYCAT_SEQUENCE WHERE name = seq_name for update;
IF val != -1 THEN
UPDATE MYCAT_SEQUENCE SET current_value = val WHERE name = seq_name;
END IF;
SELECT RELEASE_LOCK(seq_name) into seq_lock;
end if;
SELECT CONCAT(CAST((val - count + 1) as CHAR), ",", CAST(val as CHAR)) INTO retval;
RETURN retval;
END
;;
DELIMITER ;
-- ----------------------------
-- Function structure for `mycat_seq_setval`
-- ----------------------------
DROP FUNCTION IF EXISTS `mycat_seq_setval`;
DELIMITER ;;
CREATE FUNCTION `mycat_seq_setval`(seq_name VARCHAR(64), value BIGINT) RETURNS varchar(64) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
DECLARE inc INT;
SET inc = 0;
SELECT increment INTO inc FROM MYCAT_SEQUENCE WHERE name = seq_name;
UPDATE MYCAT_SEQUENCE SET current_value = value WHERE name = seq_name;
SELECT concat(CAST(value as CHAR),",",CAST(inc as CHAR)) INTO retval;
RETURN retval;
END
;;
DELIMITER ;
INSERT INTO MYCAT_SEQUENCE VALUES ('GLOBAL', 1, 1);
然后在schema.xml
、sequence_db_conf.properties
中配置:
schema.xml:
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100" randomDataNode="dn1">
<!--splitTableNames 启用<table name 属性使用逗号分割配置多个表,即多个表使用这个配置-->
<table name="cz_dept" primaryKey="id" autoIncrement="true" dataNode="dn1,dn2" rule="hash-string"/>
<table name="mycat_sequence" primaryKey="name" dataNode="dn1"/>
</schema>
sequence_db_conf.properties:
#sequence stored in datanode
GLOBAL=dn1
CZ_DEPT=dn1