在实现分库分表的情况下,数据库自增主键已经无法保证在集群中是全局唯一的主键了,因此mycat提供了全局的sequence,并且提供了本地配置、数据库配置等多种实现方式。
1. 本地文件方式
采用该方式,mycat将sequence配置到classpath目录的sequence_conf.properties文件中,在sequence_conf.properties文件做如下配置
GLOBAL_SEQ.HISIDS= GLOBAL_SEQ.MINID=1001 GLOBAL_SEQ.MAXID=100000000 GLOBAL_SEQ.CURID=1000
其中HISIDS表示历史分段(一般无特殊需要则可以不配置),MINID表示最新的ID值,MAXID表示最大的ID值,CURID表示当前的ID值。
需要启用这种方式,则首先需要在servier.xml中配置如下参数:
<system>
<property name="sequnceHandlerType">0</property>
</system>
注意:sequnceHandlerType配置为0,表示使用本地文件方式
采用这种方式的优缺点:
- 缺点:mycat重新发布后,配置文件中的sequence会恢复到初始值
- 优点:本地加载且读取速度快。
2. 数据库方式
在数据库中创建一张表名为sequence的表,有sequence的当前值(current_value)、步长(increment int 类型,指每次读取多少个sequence,假设值为K)等信息。
2.1 squence的获取步骤如下:
1)每次使用sequence时候,根据传入的sequence名称,从数据库表中 读取current_value、increment到mycat中,并将数据库中的current_value 修改为current_value + increment的值。
2)mycat将读取到的current_value+increment 作为本次使用的sequence值,在下次使用的时候,sequence自动加1,当使用increment次后,执行与步骤一相同操作。
3)mycat负责维护这张表,用到哪些sequence时,主需要在这张表插入一条记录即可,若某次读取sequence没有用完就宕机了,则本次已经读取sequence且未使用的值将会被丢弃。
若要启用这种方式,需要在server.xml中配置如下参数:
<system> <property name="sequnceHandlerType">1</property> </system>
注意:这里配置成1,表示使用数据库方式生成sequence.
2.2 数据库配置如下:
创建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;
name、current_value和increment 分别sequence的名称、当前value的值和增长步长。
插入一条sequence语句:
insert into MYCAT_SEQUENCE(name,current_value,increment) VALUES(‘GLOBAL’,10000,100);
创建相关的function
DROP FUNCTION IF EXISTS mycat_seq_currval; DELIMITER CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS varchar(64) CHARSET utf-8 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 utf-8 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 utf-8 DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment WHERE name = seq_name; RETURN mycat_seq_currval(seq_name); END DELIMITER;
sequence_db_conf.properties指定 sequence 相关配置在哪个节点上
USER_SEQ=test_dn1
使用示例:
insert into table1(id,name) values(next value for MYCATSEQ_GLOBAL,‘test’);
这样做虽然MyCat为无状态而且id有持久化,并且一次可以取出多个id,通过配置可以有主从切换。但是,id还是纯数字,没有有意义的信息,而且,MyCat主从切换并不可靠,id生成有故障,则整个服务都无法正常进行,这在架构上有单点问题,是不推荐的。
3. 时间戳方式
ID= 64 位二进制 (42(毫秒)+5(机器 ID)+5(业务编码)+12(重复累加)
server.xml:
<system> <property name="sequnceHandlerType">2</property> </system>
sequence_time_conf.properties:
WORKID=0-31 任意整数 DATAACENTERID=0-31 任意整数
3. 其他方式
3.1 通过catlet注解实现
select mycat_get_seq(‘GLOBAL‘,100);
注意:此方法获取FLOBAL的100个sequence,例如当前最大的GLOBAL是5000,则此方法返回的是5100,同时更新数据库的最大sequence值为5100,。
3.2 也可以使用zookeeper方式实现
4. 自增长主键
4.1 mysql定义自增长主键。
create table 1(‘id_’,INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,‘name_‘ INT(10) UNSIGNED NOT NULL ,PARIMARY KEY (‘id_‘))ENGINE=MYISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf-8;
4.2 mycat 定义自增长主键
在table标签中增加 autoIncrement="true":
<table name="A" primaryKey="id" autoIncrement="true" dataNode="dn1,dn2" rule="mod-long"><table>
4.3 mycat对应的sequence_db_conf.properties添加响应配置。
TABLE1=dn1
4.4 在数据库的mycat_sequenct 表中添加TABLE1表的sequence记录。