本文给大家介绍mysql全局id生成方法,涉及到mysql全局id相关知识,感兴趣的朋友一起学习吧

生产系统随着业务增长总会经历一个业务量由小变大的过程,可扩展性是考量数据库系统高可用性的一个重要指标;在单表/数据库数据量过大,更新量不断飙涨时,MySQL DBA往往会对业务系统提出sharding的方案。既然要sharding,那么不可避免的要讨论到sharding key问题,在有些业务系统中,必须保证sharding key全局唯一,比如存放商品的数据库等,那么如何生成全局唯一的ID呢,下文将从DBA的角度介绍几种常见的方案。

1、使用CAS思想

什么是CAS协议

Memcached于1.2.4版本新增CAS(Check and Set)协议类同于Java并发的CAS(Compare and Swap)原子操作,处理同一item被多个线程更改过程的并发问题

CAS的基本原理

基本原理非常简单,一言以蔽之,就是“版本号”,每个存储的数据对象,都有一个版本号。

我们可以从下面的例子来理解:

不采用CAS,则有如下的情景:

•第一步,A取出数据对象X;

•第二步,B取出数据对象X;

•第三步,B修改数据对象X,并将其放入缓存;

•第四步,A修改数据对象X,并将其放入缓存。

结论:第四步中会产生数据写入冲突。

采用CAS协议,则是如下的情景。

•第一步,A取出数据对象X,并获取到CAS-ID1;

•第二步,B取出数据对象X,并获取到CAS-ID2;

•第三步,B修改数据对象X,在写入缓存前,检查CAS-ID与缓存空间中该数据的CAS-ID是否一致。结果是“一致”,就将修改后的带有CAS-ID2的X写入到缓存。

•第四步,A修改数据对象Y,在写入缓存前,检查CAS-ID与缓存空间中该数据的CAS-ID是否一致。结果是“不一致”,则拒绝写入,返回存储失败。

这样CAS协议就用了“版本号”的思想,解决了冲突问题。(乐观锁概念)

其实这里并不是严格的CAS,而是使用了比较交换原子操作的思想。

生成思路如下:每次生成全局id时,先从sequence表中获取当前的全局最大id。然后在获取的全局id上做加1操作,加1后的值更新到数据库,如加1后的值为203,表名是users,数据表结构如下:

CREATE TABLE `SEQUENCE` (

`name` varchar(30) NOT NULL COMMENT '分表的表名',

`gid` bigint(20) NOT NULL COMMENT '最大全局id',

PRIMARY KEY (`name`)

) ENGINE=innodb

sql语句

update sequence set gid = 203 where name = 'users' and gid < 203;

sql语句的 and gid < 203 是为了保证并发环境下gid的值只增不减。

如果update语句的影响记录条数为0说明,已经有其他进程提前生成了203这个值,并写入了数据库。需要重复以上步骤从新生成。

代码实现如下:

//$name 表名

function next_id_db($name){

//获取数据库全局sequence对象

$seq_dao = Wk_Sequence_Dao_Sequence::getInstance();

$threshold = 100; //最大尝试次数

for($i = 0; $i < $threshold; $i++){

$last_id = $seq_dao->get_seq_id($name);//从数据库获取全局id

$id = $last_id +1;

$ret = $seq_dao->set_seq_id($name, $id);

if($ret){

return $id;

break;

}

}

return false;

}

2、使用全局锁

在进行并发编程时,一般都会使用锁机制。其实,全局id的生成也是解决并发问题。

生成思路如下:

在使用redis的setnx方法和memcace的add方法时,如果指定的key已经存在,则返回false。利用这个特性,实现全局锁

每次生成全局id前,先检测指定的key是否存在,如果不存在则使用redis的incr方法或者memcache的increment进行加1操作。这两个方法的返回值是加1后的值,如果存在,则程序进入循环等待状态。循环过程中不断检测key是否还存在,如果key不存在就执行上面的操作。

代码如下:

//使用redis实现

//$name 为 逻辑表名

function next_id_redis($name){

$redis = Wk_Redis_Util::getRedis();//获取redis对象

$seq_dao = Wk_Sequence_Dao_Sequence::getInstance();//获取存储全局id数据表对象

if(!is_object($redis)){

throw new Exception("fail to create redis object");

}

$max_times = 10; //最大执行次数 避免redis不可用的时候 进入死循环

while(1){

$i++;

//检测key是否存在,相当于检测锁是否存在

$ret = $redis->setnx("sequence_{$name}_flag",time());

if($ret){

break;

}

if($i > $max_times){

break;

}

$time = $redis->get("sequence_{$name}_flag");

if(is_numeric($time) && time() - $time > 1){//如果循环等待时间大于1秒,则不再等待。

break;

}

}

$id = $redis->incr("sequence_{$name}");

//如果操作失败,则从sequence表中获取全局id并加载到redis

if (intval($id) === 1 or $id === false) {

$last_id = $seq_dao->get_seq_id($name);//从数据库获取全局id

if(!is_numeric($last_id)){

throw new Exception("fail to get id from db");

}

$ret = $redis->set("sequence_{$name}",$last_id);

if($ret == false){

throw new Exception("fail to set redis key [ sequence_{$name} ]");

}

$id = $redis->incr("sequence_{$name}");

if(!is_numeric($id)){

throw new Exception("fail to incr redis key [ sequence_{$name} ]");

}

}

$seq_dao->set_seq_id($name, $id);//把生成的全局id写入数据表sequence

$redis->delete("sequence_{$name}_flag");//删除key,相当于释放锁

$db = null;

return $id;

}

3、redis和db结合

使用redis直接操作内存,可能性能会好些。但是如果redis死掉后,如何处理呢?把以上两种方案结合,提供更好的稳定性。

代码如下:

function next_id($name){

try{

return $this->next_id_redis($name);

}

catch(Exception $e){

return $this->next_id_db($name);

}

}

4、Flicker的解决方案

因为mysql本身支持auto_increment操作,很自然地,我们会想到借助这个特性来实现这个功能。Flicker在解决全局ID生成方案里就采用了MySQL自增长ID的机制(auto_increment + replace into + MyISAM)。一个生成64位ID方案具体就是这样的:

先创建单独的数据库(eg:ticket),然后创建一个表:

CREATE TABLE Tickets64 (

id bigint(20) unsigned NOT NULL auto_increment,

stub char(1) NOT NULL default '',

PRIMARY KEY (id),

UNIQUE KEY stub (stub)

) ENGINE=MyISAM

当我们插入记录后,执行SELECT * from Tickets64,查询结果就是这样的:

+-------------------+------+

| id                | stub |

+-------------------+------+

| 72157623227190423 |    a |

+-------------------+------+

在我们的应用端需要做下面这两个操作,在一个事务会话里提交:

REPLACE INTO Tickets64 (stub) VALUES ('a');

SELECT LAST_INSERT_ID();

这样我们就能拿到不断增长且不重复的ID了。

到上面为止,我们只是在单台数据库上生成ID,从高可用角度考虑,

接下来就要解决单点故障问题:Flicker启用了两台数据库服务器来生成ID,

通过区分auto_increment的起始值和步长来生成奇偶数的ID。

TicketServer1:

auto-increment-increment = 2

auto-increment-offset = 1

TicketServer2:

auto-increment-increment = 2

auto-increment-offset = 2

最后,在客户端只需要通过轮询方式取ID就可以了。

•优点:充分借助数据库的自增ID机制,提供高可靠性,生成的ID有序。

•缺点:占用两个独立的MySQL实例,有些浪费资源,成本较高。

以上内容是小编给大家分享的Mysql全局ID生成方法,希望大家喜欢。

mysql自动生成id方式_Mysql全局ID生成方法相关推荐

  1. 【转】MySQL分库分表环境下全局ID生成方案

    转载一篇博客,里面有很多的知识和思想值得我们去思考. ---------------------------------------------------------------------- 在大 ...

  2. MySQL分库分表使用Snowflake全局ID生成器(3rd)

    前言 由于考虑到以后要动态切分数据,防止将不同表切分数据到同一个表中时出现主键相等的冲突情况,这里我们使用一个全局ID生存器.重要的是他是自增的. 这边我使用Snowflake的python实现版(p ...

  3. mysql自动写入创建时间_mysql 自动记录数据插入及最后修改时间

    总结: `uptime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 应用场景: 1.在数据表中, ...

  4. mysql自动获取时间列_mysql自动获取时间日期的方法

    实现方式: 1.将字段类型设为 TIMESTAMP 2.将默认值设为 CURRENT_TIMESTAMP 举例应用: 1.MySQL 脚本实现用例 --添加CreateTime 设置默认时间 CURR ...

  5. oracle 全局id,基于SnowFlake 全局ID 生成器 go-id-worker

    snowflake的结构如下(每部分用-分开): 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 0000000 ...

  6. mysql 自动备份 发邮件_MYSQL自动备份并发送邮件工具

    最近在开发小程序,由于服务器只有一台,所以不能数据库异机备份,出于数据安全的考虑,就做了一个数据库定时备份并发送邮件到自己的邮箱的小工具,先看下工具界面 这个工具主要涉及到三个部分 1.MYSQL自动 ...

  7. MySQL分库分表环境下全局ID生成方案

    参考:http://www.cnblogs.com/qiumingcheng/p/5409491.html http://geek.csdn.net/news/detail/72973

  8. mysql常见增量恢复方式_MySQL 全备份与增量备份 全恢复与增量恢复

    一,全备份 与 全恢复 1.vim /root/db_backup/mysqldump_mraz.php,内容如下: date_default_timezone_set("PRC" ...

  9. mysql存储引擎的方式_Mysql转换表存储引擎的三种方式

    或许会有一些场景需要改变表的存储引擎,例如存储日志的表如果几乎只有insert和少量的select操作,为了追求更好的插入性能有可能会需要把存储引擎更换为MyISAM.但是,本文不建议在同一个数据库中 ...

最新文章

  1. 李子柒爆红:既然做直播能年薪过亿, 为何还要努力高考?
  2. Microbit扩展编写
  3. 使用java中的String类操作复杂的字符串
  4. 【渝粤题库】广东开放大学 秘书理论与实务 形成性考核
  5. LeetCode 204. 计数质数(质数的倍数不是质数)
  6. 理解java虚拟机工作后了解吗_JAVA入门到再次入门——深入理解JAVA虚拟机(二)|七日打卡...
  7. CVPR 2020|华为发布基于连续进化的CARS算法,0.4GPU天输出帕累托前沿
  8. thikphp 控制器
  9. ​CSDN疯狂盲盒来啦!iPhone 12、机械键盘、Switch等你来拿!
  10. git复制迁移--SmartGit
  11. 如果你知道10条以上,你就和我一样渊博了
  12. 转基因粮食的毒性,首先是因为农药
  13. 高德地图开放平台——行政区划分DistrictSearch 准确定位区域,指定某一城市的行政区
  14. 用Scratch制作手游的角色方向虚拟控制器/虚拟摇杆的方法+源码
  15. python中shift函数_Pandas Shift函数的基础入门学习笔记
  16. 传奇开外网需要映射那几个端口
  17. 用树莓派控制两盏灯(二)
  18. Java基础-常见IO五种模型
  19. cmnet和cmwap的访问
  20. 【性能测试】性能测试步骤

热门文章

  1. 计算机课程设计参考文献,计算机课程设计专著参考文献 计算机课程设计论文参考文献哪里找...
  2. OFDM学习笔记(六)(峰均值问题)
  3. 双子星量子计算机,【前沿】“前途”无量的量子科技
  4. 2020最受欢迎主动降噪蓝牙耳机盘点,五款性能超强蓝牙耳机推荐
  5. Android 动画解析(一) 逐帧动画(Frame Animation)
  6. 笔记本电脑的鼠标触控面板问题
  7. 计算机无法加载远程访问连接管理器服务,win7宽带连接提示无法加载远程访问连接管理器服务错误711怎么办...
  8. 下月起你的到手工资将有重大变化! 图解2019年个税怎么算
  9. linux ssh su - 区别,su 与 su -区别
  10. 微信朋友圈装x代码_朋友圈生成器有哪些_微信朋友圈生成器大全_微信朋友圈装逼生成器下载_飞翔软件专题...