常见的两种方案,遍布网络:
第一种:
replace方案,mysql解释:REPLACE的运行与INSERT很相像。只有一点除外,如果表中的一个旧记录与一个用于PRIMARY KEY或一个UNIQUE索引的新记录具有相同的值,则在新记录被插入之前,旧记录被删除。
CREATE TABLE `user_id_seq` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`stub` varchar(3) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `stub` (`stub`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
REPLACE INTO user_id_seq(stub) VALUES ('a');
select last_insert_id();
这种方案一般一个表对应一个类型的主键,简单明了,一个表对应一个业务的seq。但是在高并发的情况下很容易导致mysql死锁。
第二种:
CREATE TABLE `sequence` (
`name` varchar(50) NOT NULL,
`id` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
INSERT INTO `sequence` (`name`) VALUES('users');
update sequence set id=last_insert_id(id+1) where name = 'users';
select last_insert_id();
这种方案可以一个表支持多个业务的seq需求,但是太多的业务对这一个表频繁操作,如果某个业务出现锁表,就会导致其他业务无法进行。
第三种:
如果是java的项目,可以使用spring框架的MySQLMaxValueIncrementer解决,在mysql上实现原理同第二种,只是在业务层加了一段本地缓存,对于seq请求很高的业务可以较好的保障。
以上三种方案的都关系到mysql的last_insert_id()这个功能,其实关键点也就是这个last_insert_id()使我们可以通过mysql实现唯一seq的设计。
mysql中对它的解释:【对于LAST_INSERT_ID(),最近生成的ID是在服务器上按连接维护的。它不会被另一个客户端改变。即使用non-magic值(即非Null非0值)更新了另一个AUTO_INCREMENT列,也不会更改它。】
mysql如何获得上次插入行的唯一ID
http://dev.mysql.com/doc/refman/5.1/zh/apis.html#getting-unique-id
这样不管我们如何设计,只要保证select last_insert_id();之前的操作是一个连接完成的原子操作,我们就能从返回值中得到唯一的last_insert_id。