在分布式系统中,SpringBoot 实现接口幂等性( 二 )

  1. 在需要进行幂等性校验的方法上添加 @Idempotent 注解:
 @Servicepublic class UserService {@Autowiredprivate IdempotenceKeyMapper idempotenceKeyMapper;@Idempotent(expireSeconds = 60)public void createUser(String username) {// 创建用户// ...}}通过以上方式,在方法执行前会先进行幂等性校验,如果已经执行过该方法,则直接返回结果,不会再次执行 。
在实际应用中,需要考虑一些特殊情况的处理,以提高幂等性校验的准确性和可靠性 。下面列举一些可能遇到的情况:
  1. 请求超时处理:由于幂等性校验码是有过期时间的,如果客户端发起的请求在幂等性校验码过期后才到达服务器,那么该请求就不应该再被视为重复请求 。为了解决这个问题,可以在幂等性校验码表中记录请求的时间戳,并在校验幂等性校验码时进行时间戳比较,以判断请求是否超时 。
在幂等性校验码表中添加一个请求时间戳的字段,将请求时间戳一并存储,以便在校验幂等性校验码时进行时间戳比较 。
CREATE TABLE `idempotent_key` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`key` varchar(128) NOT NULL COMMENT '幂等性校验码',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`expire_time` datetime NOT NULL COMMENT '过期时间',`request_time` datetime NOT NULL COMMENT '请求时间',PRIMARY KEY (`id`),UNIQUE KEY `uk_key` (`key`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='幂等性校验码表';在进行幂等性校验时,需要先判断幂等性校验码是否过期,如果过期则不再进行校验 。
public void processRequest() {String key = generateIdempotentKey();LocalDateTime now = LocalDateTime.now();LocalDateTime expireTime = now.plusMinutes(5);LocalDateTime requestTime = now;// 将幂等性校验码和请求时间戳存入数据库中idempotentKeyDao.insert(key, expireTime, requestTime);// 判断请求是否过期LocalDateTime threshold = now.minusMinutes(5);if (requestTime.isBefore(threshold)) {// 请求已经过期,不再进行幂等性校验return;}// 进行幂等性校验boolean success = idempotentKeyDao.checkAndUpdate(key);if (!success) {// 幂等性校验失败return;}// 执行业务操作// ...}
  1. 高并发下的幂等性校验:在高并发场景下,多个请求可能同时到达服务器进行幂等性校验,这时需要保证校验的准确性和唯一性 。可以通过对幂等性校验码进行唯一索引的方式来保证每个幂等性校验码只会出现一次,避免多个请求同时通过校验 。
在幂等性校验码表的 key 字段上添加唯一索引,以保证每个幂等性校验码只会出现一次 。
ALTER TABLE `idempotent_key` ADD UNIQUE INDEX `uk_key` (`key`);在进行幂等性校验时,需要使用数据库的唯一索引进行校验 。
public boolean checkAndUpdate(String key) {// 利用数据库的唯一索引保证幂等性校验码的唯一性int affectedRows = jdbcTemplate.update("UPDATE idempotent_key SET request_count = request_count + 1 WHERE key = ?",key);return affectedRows == 1;}
  1. 幂等性校验码的重复利用:在一些场景下,比如一个请求执行失败需要重试,或者用户进行了一些撤销操作后需要再次执行该操作等,幂等性校验码可能会被多次使用 。为了避免重复利用同一个幂等性校验码导致的校验失效,可以对幂等性校验码进行标记,标记该校验码已被使用过,避免再次使用 。
在幂等性校验码表中添加一个 used 字段,标记该幂等性校验码是否已被使用过 。
在进行幂等性校验时,需要判断该幂等性校验码是否已经被使用过,如果已经被使用过,则不再进行校验 。
public boolean checkAndUpdate(String key) {// 判断幂等性校验码是否已经被使用过boolean used = jdbcTemplate.queryForObject("SELECT used FROM idempotent_key WHERE key = ?",Boolean.class,key);if (used) {// 幂等性校验码已经被使用过,不再进行校验return true;}// 将幂等性校验码标记为已使用int affectedRows = jdbcTemplate.update("UPDATE idempotent_key SET used = true WHERE key = ?",key);return affectedRows == 1;}幂等性校验码的生成规则:幂等性校验码的生成规则也需要考虑,应该根据业务的特点来确定 。可以采用随机数、UUID、请求参数哈希等方式生成幂等性校验码 。需要保证幂等性校验码在相同的请求条件下生成的结果一致 。


推荐阅读