vlambda博客
学习文章列表

使用MySQL排它锁来实现分布式全局唯一ID

最近在项目重构的过程中,遇到需要使用分布式全局唯一ID的地方。


首先来说一下什么是分布式全局唯一ID。分布式全局唯一ID指的是在分布式,高并发的情况下生成的全局唯一ID。具体可以考虑下面的场景进行理解。


假设有一个用户注册的功能,要为每个用户生成唯一的用户ID作为用户标识。表结构如下图所示。


CREATE TABLE `user` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT,  `uid` bigint unsigned NOT NULL,   PRIMARY KEY (`id`),   unique key `uid` (`uid`)   )ENGINE=InnoDB;


为了应对大量用户注册的请求,我们启动了多个用户注册的服务,这些用户注册的服务都需要插入user表。那么问题来了,该如何保证uid的全局唯一性呢?


结合项目具体的情况(原有项目已经在运行,已经生成了原始数据),采用了MySQL排他锁来实现。


具体SQL如下

INSERT INTO user(uid) select max(uid)+1  from user for update;


通过使用 select ... for update 创建排它锁,保证在同一个时刻,其他的插入线程处于阻塞状态,从而保证了 max(uid)+1 生成的uid的全局唯一性。


完成了插入操作,如果我们还需要返回刚生成的uid,应该怎么做呢?

可以使用下面的SQL进行查询。

select uid from user where id=(select last_insert_id());


需要注意的是 last_insert_id() 函数只对当前插入的线程有效。如果插入完成后,其他线程来使用select last_insert_id() 进行查询,查询到的是这个线程自己上一次的插入值,是查询不到插入线程插入的值的。


其他分布式全局唯一ID的生成策略,可以查看这篇文章,写的很详细。

https://juejin.cn/post/6844904016141369352