全局序列
基于本地的序列
在分库分表的前提下,数据库自增的方式已经没有办法保证自增主键的全局唯一性了。如果,各个分表都独立地去自增长,而不考虑其他表的主键情况,此时的数据是有问题的。Mycat提供了全局序列号设置,保证该分片表的主键是全局唯一的,其中的一种主键生成策略便是,本地文件的方式。
使用本地文件的方式来进行数据插入主要有两步:
(1) 在server.xml文件中指定全局序列的生成方式为本地文件方式,即指定sequnceHandlerType属性值为0
(2) 配置sequence_conf.properties文件该表的主键值
TEST_SHARDING_BY_ACCOUNTING_DATE.HISIDS=
TEST_SHARDING_BY_ACCOUNTING_DATE.CURID=11
TEST_SHARDING_BY_ACCOUNTING_DATE.MINID=1
TEST_SHARDING_BY_ACCOUNTING_DATE.MAXID=10000000
比如这里代表了TEST_SHARDING_BY_ACCOUNTING_DATE这张表主键的当前值为11,最小值为1,最大值为10000000
在插入下一条数据时,会将当前值+1作为新的主键ID并修改该文件的CURID的值。
① 优点:本地加载,读取速度较快
② 缺点:抗风险能力差,Mycat 所在主机宕机后,无法读取本地文件。
基于数据库的序列
数据库方式利用数据库一个表 来进行计数累加。但是并不是每次生成序列都读写数据库,这样效率太低。
Mycat 会预加载一部分号段到 Mycat 的内存中,这样大部分读写序列都是在内存中完成的。如果内存中的号段用完了 Mycat 会再向数据库要一次。
问:那如果 Mycat 崩溃了 ,那内存中的序列岂不是都没了?是的。如果是这样,那么 Mycat 启动后会向数据库申请新的号段,原有号段会弃用。
也就是说如果 Mycat 重启,那么损失是当前的号段没用完的号码,但是不会因此出现主键重复
建库序列脚本
#在 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;
reuturn 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_calue+increment where name=seq_name;
return mycat_seq_currval(seq_name);
end $$
DELIMITER ;
#初始化序列记录表
insert into mycat_sequence(name,current_value,increment) values('ORDER',400000,10);
2.修改mycat配置
#修改sequence_db_conf.properties
vim sequence_db_conf.properties
#意思是ORDERS这个序列在dn1这个节点上
#修改 server.xml
vim server.xml
#全局序列类型 0:本地文件 1:数据库方式 2:时间戳
自主生成全局序列
可在 java 项目里自己生成全局序列,如下:
① 根据业务逻辑组合
② 可以利用 redis 的单线程原子性 incr 来生成序列
但,自主生成需要单独在工程中用 java 代码实现,还是推荐使用 Mycat 自带全局序列。
Mycat弱XA事务
弱事务情景&分析
在分布式事务中应该考虑这三种情况:
(1) 单SQL不垮分片:事务中的单条SQL在单个节点上执行
(2) 单SQL跨分片:事务中的单条SQL在多个节点上执行
(3) 事务内多个SQL,在不同的分片上执行
其中,第一种情况,单一SQL仅仅在一个dataNode上执行,此时Mycat事务模式跟标准的数据库事务模式一样,要么提交要么回滚。
而对于第二种和第三种的事务,Mycat执行的一种”弱XA事务“模式,此模式的逻辑如下:首先事务内的SQL在各自的分片上执行并返回状态码,若某个分片上的返回码为ERROR,则Mycat认为事务失败,应用端只能回滚(rollback)事务,Mycat收到回滚指令后,依次回滚事务中涉及到的所有分片;若事务中的所有SQL的执行都返回成功
(OK)的返回码,则应用程序提交事务的时候,Mycat会同时向事务中涉及到的节点发送提交事务的指令commit。但是如果各个节点预执行语句都成功,各个节点在执行commit提交事务时,如果一个节点发生异常,比如某节点突然down机或者由于网络故障没有收到commit指令,则mycat无法回滚已提交的事务,会出现数据不一致的情况。从这点来说他是一个弱事务。
按照官方是说法,这种弱事务模型的出错的概率是很小的,基本上能满足绝大部分的企业开发需求。