数据库幂等性的实现方法
使用数据库实现幂等性的方法有三种:
- 通过悲观锁来实现幂等性
- 通过唯一索引来实现幂等性
- 通过乐观锁来实现幂等性
接下来我们分别来看这些实现方式的具体执行过程。
① 悲观锁
使用悲观锁实现幂等性,一般是配合事务一起来实现,在没有使用悲观锁时,我们通常的执行过程是这样的,首先来判断数据的状态,执行 SQL 如下:
select status from table_name where id='xxx';
然后再进行添加操作:
insert into table_name (id) values ('xxx');
最后再进行状态的修改:
update table_name set status='xxx';
但这种情况因为是非原子操作,所以在高并发环境下可能会造成一个业务被执行两次的问题,当一个程序在执行中时,而另一个程序也开始状态判断的操作。因为第一个程序还未来得及更改状态,所以第二个程序也能执行成功,这就导致一个业务被执行了两次。
在这种情况下我们就可以使用悲观锁来避免问题的产生,实现 SQL 如下所示:
begin; # 1.开始事务
select * from table_name where id='xxx' for update; # 2.查询状态
insert into table_name (id) values ('xxx'); # 3.添加操作
update table_name set status='xxx'; # 4.更改操作
commit; # 5.提交事务
在实现的过程中需要注意以下两个问题:
如果使用的是 MySQL 数据库,必须选用 innodb 存储引擎,因为 innodb 支持事务;
id 字段一定要是主键或者是唯一索引,不然会锁表,影响其他业务执行。
② 唯一索引
我们可以创建一个唯一索引的表来实现幂等性,在每次执行业务之前,先执行插入操作,因为唯一字段就是业务的 ID,因此如果重复插入的话会触发唯一约束而导致插入失败。在这种情况下(插入失败)我们就可以判定它为重复提交的请求。
唯一索引表的创建示例如下:
CREATE TABLE `table_name` (
`id` int NOT NULL AUTO_INCREMENT,
`orderid` varchar(32) NOT NULL DEFAULT '' COMMENT '唯一id',
PRIMARY KEY (`id`),
UNIQUE KEY `uq_orderid` (`orderid`) COMMENT '唯一约束'
) ENGINE=InnoDB;
③ 乐观锁
乐观锁是指在执行数据操作时(更改或添加)进行加锁操作,其他时间不加锁,因此相比于整个执行过程都加锁的悲观锁来说,它的执行效率要高很多。
乐观锁可以通过版本号来实现,例如以下 SQL:
update table_name set version=version+1 where version=0;