业务ID如何设计,满足大规模并发
先前业务有大量的id生成,比如充值id,订单id,支付id等,业务id格式一般为 10160824000123 其中10代表业务类型,其中 160824代表2016年08月24日 000123代表自增长的id,当多个业务同时都要生成id的时候,一般会这么设计,先看表。
CREATE TABLE `id_create` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`type` int(11) NOT NULL COMMENT ';业务类型1充值 2订单 3支付';,
`value` bigint(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='生成表';
根据type值去生成各个业务id值,value每次+1 ,有几个问题,生成value值的时候,这个表会被同时很多程序同时在跑,只要一个业务受损,其它业务必然也受损。
改进:
CREATE TABLE `id_create_1` (
`id` bigint(20) NOT NULL AUTO_INCREMENT
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='生成表1';
CREATE TABLE `id_create_2` (
`id` bigint(20) NOT NULL AUTO_INCREMENT
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='生成表2';
CREATE TABLE `id_create_3` (
`id` bigint(20) NOT NULL AUTO_INCREMENT
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='生成表3';
这样避免业务相互竞争的情况,但还有几个问题没有解决。
1、InnoDB在事务会锁表
2、事务回滚导致业务生成的值有时候大有时候小,
总结,不能采用InnoDB,必须采用MyISAM 引擎,不能 回滚,必须永远成功。
看下面设计的表
CREATE TABLE `id_1` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`stub` tinyint(1) NOT NULL COMMENT ';该值不允许修改变更';,
PRIMARY KEY (`id`),
UNIQUE KEY `stub` (`stub`)
) ENGINE=MyISAM
sql语句:
REPLACE INTO id_1(stub) VALUES(1)
然后去获取刚刚执行的last_insert_id
字段stub的值设为1,每次replace的值也是为1,这时id值会自增1,完美解决并发和锁表的问题。
后附一个yii2程序做为参考,其它类似:
$db = Yii::$app->db;
$sql = "REPLACE INTO id_1(stub) VALUES(1)";
$flag = $db->createCommand($sql)->execute();
$id = $db->getLastInsertID();