原创

mycat的全局序列号几种实现方式

在实现分库分表的情况下,数据库自增主键已经无法保证自增主键的全局唯一,为此,mycat提供了全局sequence,并且提供了包含本地配置和数据库配置等多种实现方式。

1、本地文件方式

使用此方式的时候,mycat讲sequence配置到文件中,当使用到sequence中的配置,mycat会更新sequence_conf.properties文件中sequence当前的值。
配置方式:在 sequence_conf.properties 文件中做如下配置:
GLOBAL_SEQ.HISIDS=
GLOBAL_SEQ.MINID=10001
GLOBAL_SEQ.MAXID=20000
GLOBAL_SEQ.CURID=10000

其中 HISIDS 表示使用过的历史分段(一般无特殊需要可不配置), MINID 表示最小 ID 值, MAXID 表示最大
ID 值, CURID 表示当前 ID 值。
server.xml 中配置:

<system><property name="sequnceHandlerType">0</property></system>

注: sequnceHandlerType 需要配置为 0,表示使用本地文件方式。

案例使用:

create table tab1(id int primary key,name varchar(10));
insert into tab1(id,name) values(next value for mycatseq_global,'test1');
insert into tab1(id,name) values(next value for mycatseq_global,'test2');
insert into tab1(id,name) values(next value for mycatseq_global,'test3');

缺点:当mycat重新发布后,配置文件中的sequence会恢复到初始值
优点:本地加载,读取速度较快

2、数据库方式

在数据库中建立一张表,存放sequence名称(name),sequence当前值(current_value),步长(increment int类型,每次读取多少个sequence,假设为K)等信息;

获取数据步骤:
a、当初次使用该sequence时,根据传入的sequence名称,从数据库这张表中读取current_value和increment到mycat中,并将数据库中的current_value设置为原current_value值+increment值。
b、mycat将读取到current_value+increment作为本次要使用的sequence值,下次使用时,自动加1,当使用increment次后,执行步骤1中的操作
c、mycat负责维护这张表,用到哪些sequence,只需要在这张表中插入一条记录即可,若某次读取的sequence没有用完,系统就停掉了,则这次读取的sequence剩余值不会再使用

配置方式:
a、修改server.xml文件
<system><property name="sequnceHandlerType">1</property></system>

b、修改schema.xml文件

<table name="test" primaryKey="id" autoIncrement="true" dataNode="dn1,dn2,dn3" rule="mod-long"/>
<table name="mycat_sequence" primaryKey="name" dataNode="dn2"/>

c、修改mycat配置文件sequence_db_conf.properties,添加属性值

#sequence stored in datanode
GLOBAL=dn1
COMPANY=dn1
CUSTOMER=dn1
ORDERS=dn1
MYCAT=dn2

d、在dn2上添加mycat_sequence表

DROP TABLE IF EXISTS mycat_sequence;
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;

e、在dn2上的mycat_sequence表中插入初始记录

INSERT INTO mycat_sequence(name,current_value,increment) VALUES ('mycat', -99, 100);

f、在dn2上创建函数

--创建函数
DROP FUNCTION IF EXISTS mycat_seq_currval;
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值
DROP FUNCTION IF EXISTS mycat_seq_setval;
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值
DROP FUNCTION IF EXISTS mycat_seq_nextval;
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 ;

数据测试:
a、插入数据表

create table test(id int,name varchar(10));

b、查询对应的序列数据表

SELECT * FROM mycat_sequence;

c、向表中插入数据,可以多执行几次

insert into test(id,name) values(next value for MYCATSEQ_MYCAT,(select database()));

d、查询添加的数据

SELECT * FROM test order by id asc;

e、重新启动mycat,重新添加数据,查看结果,重启之后从101开始

SELECT * FROM mycat_sequence;

f、重新查询数据表test

SELECT * FROM test order by id asc;

大家在使用的时候会发现报错的情况,这个错误的原因不是因为我们的配置,是因为我们的版本问题,简单替换下版本即可。
mysql> insert into test(id,name) values(next value for MYCATSEQ_MYCAT,(select database()));
ERROR 1003 (HY000): mycat sequnce err.java.lang.NumberFormatException: null

3、本地时间戳方式

ID= 64 位二进制 (42(毫秒)+5(机器 ID)+5(业务编码)+12(重复累加)。
换算成十进制为 18 位数的 long 类型,每毫秒可以并发 12 位二进制的累加。

使用方式:
a、配置server.xml文件
<property name="sequnceHandlerType">2</property>

b、修改sequence_time_conf.properties

WORKID=06 #任意整数
DATAACENTERID=06 #任意整数

c、修改schema.xml文件

<table name="test2" dataNode="dn1,dn2,dn3" primaryKey="id" autoIncrement="true" rule="mod-long" />

d、启动mycat,并且创建表进行测试

create table test2(id bigint auto_increment primary key,xm varchar(32));
insert into test2(id,xm) values(next value for MYCATSEQ_GLOBAL,'lisi') ; 

此方式的优点是配置简单,但是缺点也很明显就是18位的id太长,需要耗费多余的存储空间。

4、自定义全局序列

用户还可以在程序中自定义全局序列,通过java代码来实现,这种方式一般比较麻烦,因此在能使用mycat提供的方式满足需求的前提下一般不需要自己通过java代码来实现。

5、分布式ZK ID生成器

如果在搭建的时候使用了zookeeper,也可以使用zk来生成对应的id,此方式需要zk的配合,此处不再展示,有兴趣的同学下去自己演示即可。

本文链接地址:http://www.ysxbohui.com/article/101

正文到此结束