【java面试之一】如何实现接口幂等性?什么是幂等性?

535 阅读2分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

幂等性说的是:如何防止接口的重复无效请求。

对于一个接口而言,无论调用了多少次,最终得到的结果都是一样的。

四种解决方法:

  1. 前端拦截。不安全,可能被专业人士修改,跳过该过程。
  2. 使用数据库实现幂等性
  3. 使用 JVM 锁实现幂等性。缺点:只能引用于单机环境
  4. 使用分布式锁实现幂等性。通常使用redis或者zookeeper实现分布式锁。保证分布式锁的key是业务id的唯一标识。

1 悲观锁实现

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 字段一定要是主键或者是唯一索引,不然会锁表,影响其他业务执行。

2 唯一索引实现

在每次执行业务之前,先执行插入操作,因为唯一字段就是业务的 ID,因此如果重复插入的话会触发唯一约束而导致插入失败。在这种情况下(插入失败)我们就可以判定它为重复提交的请求。

3 乐观锁实现

版本号实现乐观锁。

update table_name set version=version+1 where version=0;

不使用分布式的情况下可以使用这种方式。

4 JVM 锁实现幂等性

使用 Lock 或者 Synchronized 实现。

流程:

  1. 使用 Lock 对代码块加锁
  2. 然后判断订单是否已经被处理过,
  3. 如果未处理则开启事务执行订单处理,处理完成之后提交事务并释放锁。

5 分布式锁实现

比如说用redis实现分布式锁:

127.0.0.1:6379> set lock true ex 30 nx
OK # 创建锁成功

因为 nx 是 not exist,所以,如果创建锁成功,表示请求成功,否则表示重复请求,不做处理。

  1. 幂等性的关键步骤

实现幂等性的关键步骤分为以下三个:

  • 每个请求操作必须有唯一的 ID,而这个 ID 就是用来表示此业务是否被执行过的关键凭证,例如,订单支付业务的请求,就要使用订单的 ID 作为幂等性验证的 Key;
  • 每次执行业务之前必须要先判断此业务是否已经被处理过;
  • 第一次业务处理完成之后,要把此业务处理的状态进行保存,比如存储到 Redis 中或者是数据库中,这样才能防止业务被重复处理。

说明:本文内容整理自拉钩教育《java源码剖析34讲》 在这里插入图片描述