产生背景
使用了mycat进行了分表后,如果还使用原来的mysql数据库自增序列(auto increment)将会造成id重复,所以,在使用了mycat进行了表数据水平切分后,数据按照一定的规则进行分布,id自增序列需要使用mycat的全局序列。
全局序列的三种方式
- 本地文件【0】
在mycat上生成一个文件,里面存放id,抗风险能力差,但凡mycat故障,备机mycat不知道文件记录的id到哪个值了。 - 数据库方式【1】
让某个主机的数据库产生id,每次提供一个范围(比如:1 ~ 100)的序列给mycat用,使用完了,再提供新的范围(如:101 ~ 200),如果mycat故障了,备机从数据库获取新的范围段的序列继续分配,那些因为mycat故障而未使用完的那部分id被丢弃,该方式使用普遍,相对合理。原理:
利用数据库一个表 来进行计数累加。但是并不是每次生成序列都读写数据库,这样效率太低;mycat会预加载一部分号段到mycat内存中,这样大部分读写序列都是在内存中完成的。如果内存中号段用完了,mycat会再向数据库要一次。
问:如果mycat崩溃了,内存中的序列岂不是都没了?
是的,如果是这样,那么mycat启动后会向数据库申请新的号段,原有号段会被弃用。
也就是说,如果mycat重启,那么损失是当前号段没用完的号码,虽然有些损失,但是不会因此产生主键重复。 - 时间戳方式【2】
实现方式很优秀,但是值太长了(18位),浪费存储空间。 - 自主生成
插入数据的时候,使用者自己根据算法或规则生成不重复的值。
数据库方式【1】
在dn1数据结点执行如下sql创建相关 table 和 function
mysql -uroot -p'root' -P 3306 -h 192.168.78.120
use order190401
CREATE TABLE MYCAT_SEQUENCE (
name VARCHAR(50) NOT NULL, #名称
current_value INT NOT NULL, #当前value
increment INT NOT NULL DEFAULT 100, #mycat在数据库中一次读取多少个sequence
PRIMARY KEY(name)
) ENGINE=InnoDB;
DELIMITER $$
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64)
DETERMINISTIC
BEGIN
DECLARE retval VARCHAR(64);
SET retval="-999999999,null";
SELECT CONCAT(CAST(current_value AS CHAR), "," ,CAST(increment AS CHAR)) INTO retval
FROM MYCAT_SEQUENCE WHERE `name`=seq_name;
RETURN retval;
END $$
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),value INTEGER) RETURNS varchar(64)
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = value
WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS varchar(64)
DETERMINISTIC
BEGIN
UPDATE MYCAT_SEQUENCE
SET current_value = current_value + increment WHERE name = seq_name;
RETURN mycat_seq_currval(seq_name);
END $$
DELIMITER ;
select * from MYCAT_SEQUENCE;
TRUNCATE TABLE MYCAT_SEQUENCE;
-- 增加要用的序列
insert into MYCAT_SEQUENCE(name,current_value,increment) values('ORDERS',400000,100);
mysql> select * from MYCAT_SEQUENCE;
+--------+---------------+-----------+
| name | current_value | increment |
+--------+---------------+-----------+
| ORDERS | 400000 | 100 |
+--------+---------------+-----------+
1 row in set (0.00 sec)
mysql>
修改mycat配置
配置sequence_db_conf.properties,指定sequence相关配置在哪个节点上:
vim sequence_db_conf.properties
ORDERS=dn1
指定sequenceHandlerType=1,为数据库方式。(0=本地文件、1=数据库、2=时间戳)
vim server.xml
<property name="sequnceHandlerType">1</property>
重启mycat,连接mycat,进行测试
mysql -umycat -p'123456' -P 8066 -h 192.168.78.120
use TESTDB
insert into orders(id,amount,customer_id,order_type) values(next value for MYCATSEQ_ORDERS,1000,101,102);
insert into orders(id,amount,customer_id,order_type) values(next value for MYCATSEQ_ORDERS,1000,101,102);
insert into orders(id,amount,customer_id,order_type) values(next value for MYCATSEQ_ORDERS,1000,101,102);
mysql> select * from orders;
+--------+------------+-------------+-----------+
| id | order_type | customer_id | amount |
+--------+------------+-------------+-----------+
| 1 | 101 | 100 | 100100.00 |
| 2 | 101 | 100 | 100300.00 |
| 6 | 102 | 100 | 100020.00 |
| 3 | 101 | 101 | 120000.00 |
| 4 | 101 | 101 | 103000.00 |
| 5 | 102 | 101 | 100400.00 |
| 400100 | 102 | 101 | 1000.00 |
| 400101 | 102 | 101 | 1000.00 |
| 400102 | 102 | 101 | 1000.00 |
| 400103 | 102 | 101 | 1000.00 |
+--------+------------+-------------+-----------+
10 rows in set (0.08 sec)
mysql>
验证成功,如果mycat故障了,修复后,再次插入数据,orders表的id会从 400200 开始递增。
更详细参考:https://blog.csdn.net/cold___play/article/details/107520844
视频教程:https://www.bilibili.com/video/BV12b411K7Zu?p=350&spm_id_from=pageDriver