介绍
在单节点的数据库中可以使用数据库自带的自增主键.而在分库分表的情况下,数据库自增主键无法保证自增主键的全局唯一.在使用全局主键可以使用mycat自带的方式
如使用本地的数据库本地自增主键id.当向mycat插入一条数据被分配到节点1.在第一条节点会出现id = 1.再次向mycat插入一条数据被分配到节点2.因为节点2也没有数据,则在节点2同样会生成id=1的数据.这样就导致了主键重复的现象.
mysql本身对非自增主键使用last_insert_id()返回0.只有是自增主键才能得到返回值. 在mycat中使用自增主键功能.但是mysql节点表没有定义auto_increment.那么在Mycat中调用last_insert-id()也是返回0.
更新配置
# 在下面使用的动态更新配置都执行了如下命
# 连接mycat管理端默认9066
mysql -uroot -proot -h192.168.128.120 -P 9066
# 重新加载全部配置文件
reload @@config_all;
# 选择库后重新加载schema.xml配置
reload @@config;
生成方式
本地文件
将主键保存到配置文件中.当需要使用主键时mycat会读取配置文件中主键.根据上一次的主键生成新的主键.同时将配置中的主键更新.本地加载读取速度快.但是不利于mycat集群使用.同时mycat重新发布后,sequence会恢复到初始值.
配置
# 查看本地文件主键的配置
vi conf/sequence_conf.properties
# 部分参数
GLOBAL.HISIDS= # 使用过的历史分段(无特殊需要可不配置)
GLOBAL.MINID=10001 # 最小ID值
GLOBAL.MAXID=20000000 # 最大ID值
GLOBAL.CURID=10000 # 当前ID值
启用
<!-- 修改配置中的server.xml中下面标签的值为0 -->
<system>
<property name="sequnceHandlerType">0</property>
</system>
演示
# 插入数据 如果重加载配置无法插入重启mycat.
insert into blog_user(id,name,password,mail,nickName) values("next value for MYCATSEQ_GLOBAL",'hello',123456,'4325532@qq.com','要吃包子哦');
# 查看结果
select id,name,nickName from blog_user;
+-------+---------------+-----------------+
| id | name | nickName |
+-------+---------------+-----------------+
| 2 | 534511019 | 羡仙 |
| 4 | 534511021 | 玩fgo吗 |
| 6 | 534511023 | 学php吗 |
| 8 | 534511025 | 不想上班 |
| 10002 | hello | 要吃包子哦 |
| 1 | qvbilam | qvbilam |
| 3 | 534511020 | 打王者吗 |
| 5 | 534511022 | 学mysql吗 |
| 7 | 534511024 | 学redis吗 |
| 9 | local_primary | 今天周日 |
+-------+---------------+-----------------+
查看mycat全局配置
cat conf/sequence_conf.properties | grep GLOBAL.CURID
# 当前主键id正好时10002
GLOBAL.CURID=10002
数据库
和本地文件的方式差不多,只是将主键保存到数据表中. 虽然数据库节点之间的数据可以互相同步.但是当数据量频繁的增加.那么mycat会频繁的读取表中的数据.在复制集群中如果出现宕机也无法保证数据同步更新造成主键一致的问题.
配置
创建表
在数据节点执行
-- 在节点数据库执行, 不是在mycat中执行.
use blog;
drop table if exists MYCAT_SEQUENCE;
create table MYCAT_SEQUENCE(
name varchar(50) not null comment '名称',
current_value int not null comment '当前值',
increment int not null default 10010 comment '增长长度',
primary key(name)
)engine = InnoDB;
-- 插入记录值
insert into MYCAT_SEQUENCE(name, current_value, increment)
values('GLOBAL', 10010, 5);
创建方法
在数据节点中执行.
获取当前主键值与增长长度
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 ;
设置主键值
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 = current_value + increment where name = seq_name;
return mycat_seq_currval(seq_name);
end
;;
delimiter ;
获取下一个主键值
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 ;
启用
在mycat中执行.
修改配置
<!-- 修改配置中的server.xml中下面标签的值为1 -->
<system>
<property name="sequnceHandlerType">1</property>
</system>
演示
-- 连接mycat执行
insert into blog_user(id,name,mail,nickName)
values
("next value for MYCATSEQ_GLOBAL",'534510','534510@163.com','明天上班?'),
("next value for MYCATSEQ_GLOBAL",'534511','534511@163.com','明天上班!');
insert into blog_user(id,name,mail,nickName)
values
("next value for MYCATSEQ_GLOBAL",'534512','534514@163.com','不想上班!'),;
-- 验证结果
select id,nickName from blog_user where id > 10000;
+-------+-----------------+
| id | nickName |
+-------+-----------------+
| 10002 | 要吃包子哦 |
| 10016 | 明天上班! |
| 10015 | 明天上班? |
| 10017 | 不想上班! |
+-------+-----------------+
4 rows in set (0.01 sec)
本地时间戳
id = 64位二进制 ( 42毫秒 + 5机器id + 5业务编码 + 12重复累加 )换算成十进制为18位数的long类型,每毫秒可以并发12位二进制的累加.
配置
# 编辑时间戳配置
vi conf/sequence_time_conf.properties
# 修改内容如下
WORKID=01 # 0-31任意整数.机器id
DATAACENTERID=01 # 0-31任意整数.唯一标识
启用
<!-- 修改配置中的server.xml中下面标签的值为2 -->
<system>
<property name="sequnceHandlerType">2</property>
</system>
演示
主键值要足够长才能写入.
# 节点中创建连接数据表
CREATE TABLE blog_links (
id varchar(64),
name varchar(255) NULL,
url varchar(255) NULL,
primary key(id)
);
insert into blog_links (name,url)
values
('baidu','www.baidu.com'),
('sohu','www.sohu.com');
# 验证
select * from blog_links;
+---------------------+-------+---------------+
| id | name | url |
+---------------------+-------+---------------+
| 1376078653254930432 | baidu | www.baidu.com |
| 1376078653254930433 | sohu | www.sohu.com |
+---------------------+-------+---------------+
2 rows in set (0.06 sec)
增加虚拟表.
<schema name="blog" checkSQLschema="true" sqlMaxLimit="100" randomDataNode="dn1">
<table name="blog_contents" dataNode="dn1,dn2" rule="mod-long" splitTableNames ="true"/>
<table name="blog_user" dataNode="dn1,dn2" rule="mod-long" splitTableNames ="true"/>
<table name="blog_links" dataNode="dn1" primaryKey="id" autoIncrement="true" splitTableNames ="true"/>
</schema>
分布式ZK
使用zookeeper生成主键
安装
# 搜索zk镜像
docker search zookeeper
# 拉取镜像
docker pull zookeeper
# 运行容器
docker run -d --name zk -p 2181:2181 -p 2888:2888 -p 3888:3888 zookeeper
配置
# 编辑zk连接信息配置
vi conf/myid.properties
loadZk=true # 启用zk
zkURL=192.168.124.17:2181 # 定义zk连接服务器端口号
clusterId=mycat-cluster-1 # 自定义zk 集群名称
myid=mycat_fz_01 # 自定义mycat主机名
clusterNodes=mycat_fz_01 # mycat主机名
# 编辑zk配置
vi conf/sequence_distributed_conf.properties
# 修改内容如下
INSTANCEID=ZK
CLUSTERID=01
启用
<!-- 修改配置中的server.xml中下面标签的值为3 -->
<system>
<property name="sequnceHandlerType">3</property>
</system>
演示
-- 插入数据
insert into blog_links (name,url)
values
('qvbilam','www.qvbilam.com'),
('yibei','blog.yibeiqwq.cn');
-- 查看结果
select * from blog_links;
+---------------------+---------+------------------+
| id | name | url |
+---------------------+---------+------------------+
| 1376078653254930432 | baidu | www.baidu.com |
| 1376078653254930433 | sohu | www.sohu.com |
| 8137966777420251264 | qvbilam | www.qvbilam.com |
| 8137966777420251265 | yibei | blog.yibeiqwq.cn |
+---------------------+---------+------------------+
4 rows in set (0.01 sec)
自增ZK
配置
myid.properties`配置与分布式ZK配置相同.
虚拟表配置
<!-- 修改配置schema.xml中虚拟表为自增 -->
<table name="blog_links" dataNode="dn1" primaryKey="id" autoIncrement="true" splitTableNames ="true"/>
数据表结构
CREATE TABLE `blog_links` (
`id` varchar(64) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
主键配置
# conf/sequence_conf.properties
BLOG_LINKS.HISIDS=
BLOG_LINKS.MINID=0
BLOG_LINKS.CURID=0
BLOG_LINKS.MAXID=0
启用
<!-- 修改配置中的server.xml中下面标签的值为4 -->
<system>
<property name="sequnceHandlerType">4</property>
</system>
演示
-- 删除之前的数据
delete from blog_links where id > 1;
-- 新增两条数据
insert into blog_links (name,url)
values
('test','www.baidu.com'),
('tlbb','www.tlbb.com');
-- 查看结果
select * from blog_links;
+----+------+---------------+
| id | name | url |
+----+------+---------------+
| 1 | test | www.baidu.com |
| 2 | tlbb | www.tlbb.com |
+----+------+---------------+
查看与重置自增id
# docker 查看pid 391e3a90639d
docker ps
# docker 进入容器
docker exec -it 391e3a90639d /bin/bash
# 进入zk命令
zkCli.sh
# 查看自增id /mycat/节点名称/.../.../报名/seq
get /mycat/mycat-cluster-1/sequences/incr_sequence/BLOG_LINKS/seq
# 返回当前自增id为2
2
# 重置自增id为10
set /mycat/mycat-cluster-1/sequences/incr_sequence/BLOG_LINKS/seq 10
验证重置后的自增id
-- 插入数据
insert into blog_links (name,url)
values
('mhxy','www.mhxy.com'),
('sohu','www.sohu.com');
-- 查看结果
select * from blog_links;
+----+------+---------------+
| id | name | url |
+----+------+---------------+
| 1 | test | www.baidu.com |
| 11 | mhxy | www.mhxy.com |
| 12 | sohu | www.sohu.com |
| 2 | tlbb | www.tlbb.com |
+----+------+---------------+
-- myca查看自增id 同样无效
select last_insert_id();
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 0 |
+------------------+