Mycat(水平拆分--分表 全局序列)
在实现分库分表的情况下,数据库自增主键已经无法保证自增主键的全局唯一。为此Mycat提供了全局sequence,并且提供了包含本地配置和数据库配置等多种实现方式。
1、本地文件
此方式 mycat 将sequence 配置到文件中,当使用到 sequence 中的配置后, Mycat 会更下 classpath 中的 sequence_conf.properties 文件中的sequence当前的值。
-
优点:本地加载,读取速度较快
-
缺点:抗风险能力差, Mycat所在宿主机宕机后,无法读取本地文件。
2.数据库方式
原理:在数据库中建立一张表(表名MYCAT_SEQUENCE),存放 sequence 名称(name),sequence 当前值(current_value),步长(increment,每次读取多少个 sequence)等信息;
Sequence 获取步骤:
-
当初次使用该 sequence 时,根据传入的 sequence 名称,从数据库这张表中读取 current_value,和increment (得到一个sequence号段)到 MyCat 中,并将数据库中的这张表的 current_value 设置为原 current_value 值+increment 值;
-
Mycat 将读取到 current_value+1 作为每次插入数据要使用的 sequence 值,当使用 increment 次后,执行上面步骤相同的操作;
-
若Mycat某次读取的sequence号段还有一串值没有用完,系统就停掉了,则这次读取的 sequence 号段的剩余值不会再使用,没了就没了,只需保证每次插入数据的sequence值是唯一的;
切换到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;
为MYCAT_SEQUENCE表插入数据(序列名 起始值 步长):
INSERT INTO MYCAT_SEQUENCE(name,current_value,increment) VALUES (‘GLOBAL’, 100000,100);
创建相应的函数一:传入序列名,获取当前sequence的值
DELIMITER $$ CREATE FUNCTION mycat_seq_currval(SEQ_NAME VARCHAR(50)) RETURNS VARCHAR(64) CHARSET utf8 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 ;
创建相应的函数二:给指定sequence设定当前值(指定具体value)
DELIMITER $$ CREATE FUNCTION mycat_seq_setval(SEQ_NAME VARCHAR(50),VALUE INTEGER) RETURNS VARCHAR(64) CHARSET UTF8 DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET CURRENT_VALUE = VALUE WHERE NAME = SEQ_NAME; RETURN MYCAT_SEQ_CURRVAL(SEQ_NAME); END$$ DELIMITER ;
创建相应的函数三:给指定sequence设定当前值(当前值=原当前值+步长)
DELIMITER $$ CREATE FUNCTION mycat_seq_nextval(SEQ_NAME VARCHAR(50)) RETURNS VARCHAR(64) CHARSET UTF8 DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET CURRENT_VALUE = CURRENT_VALUE + INCREMENT WHERE NAME = SEQ_NAME; RETURN MYCAT_SEQ_CURRVAL(SEQ_NAME); END$$ DELIMITER ;
配置Mycat的/conf/sequence_db_conf.properties(指明所用的序列名,以及MYCAT_SEQUENCE表在哪个分片节点上)
GLOBAL=dn1
配置Mycat的/conf/server.xml,表示所用的全局序列方式为数据库方式
<property name="sequnceHandlerType">1</property>
重启Mycat
INSERT INTO orders(id,amount,customer_id,order_type) VALUES(next value for MYCATSEQ_GLOBAL,1000,101,102);
此时在Mycat里select一下数据,可以看到插入的数据记录已经自动获取主键值
3.时间戳方式
全局序列 ID = 64 位 二进制 42(毫秒 )+ 5(机器 ID)+5(业务编码) + 12(重复累加)换算成十进制为 18 位数的 long 类型,每毫秒可以并发 12 位二进制的累加。
-
优点:配置简单
-
缺点:18位ID过长
注:后续补上
4.自主生成全局序列
可以在java项目里自己生成全局序列,
-
根据业务逻辑组合
-
可以利用redis的单线程原子性 incr 来生成序列
但,自主生成需要单独在工程中用java代码实现,还是推荐使用Mycat 自带全局序列