在实现分库分表的情况下,数据库自增主键已无法保证自增主键的全局唯一。为此,mycat提供了以下几种解决方式:
一、本地文件
比方式mycat将sequence配置到文件中,当使用到sequence中的配置后,mycat会更下classpath中的sequence_conf.properties文件中sequence当前的值。
优点:本地加载,读取速度较快。
缺点:抗风险能力差,mycat所在主机宕机后,无法读取本地文件。
二、数据库方式(推荐)
利用数据库一个表来进行计数累加。mycat会预加载一部分号段到mycat的内存中,这样大部分读写序列都在内存中完成,如果内存中的号段用完了mycat会再向数据库要一次。如果mycat重启,那么损失是当前的号段没用完的号码,但是不会因此出现主键重复。
1、创建序列脚本
#在 dn1 上创建全局序列表
CREATE TABLE MYCAT_SEQUENCE (NAME VARCHAR(50) NOT NULL,current_value INT NOT
NULL,increment INT NOT NULL DEFAULT 100, 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 $$
DELIMITER ;
DELIMITER $$
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 $$
DELIMITER ;
DELIMITER $$
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 ;
#初始化序列表记录
INSERT INTO MYCAT_SEQUENCE(NAME,current_value,increment) VALUES ('ORDERS', 400000,
100);
2、修改mycat配置
vim sequence_db_conf.properties
意思是orders这个序列在dn1这个节点上,具体dn1是哪台机器需要查看schema.xml
vim /usr/local/mycal/conf/server.xml
<property name="sequnceHandlerType">1</property>
全局序列类型(sequnceHandlerType):0-本地文件;1-数据库方式;2-时间戳方式
3、重启mycat
mycat console
4、写入数据并验证
#登录 Mycat,插入数据
insert into orders(id,amount,customer_id,order_type) values(next value for MYCATSEQ_ORDERS,1000,101,102);
重启mycat后再写入数据并验证
三、时间戳方式
全局序列ID=64位二进制(42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))换算成十进制为18位数的long类型,每毫秒可以并发12位二进制的累加。
优点:配置简单
缺点:18位ID过长
四、自主生成全局序列
可在项目里自己生成全局序列,如下
1、根据业务逻辑组合
2、利用redis的单线程原子性incr来生成序列