日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
在分布式系統(tǒng)中,SpringBoot實現(xiàn)接口冪等性

在分布式系統(tǒng)中,接口冪等性是一個非常重要的概念,它保證了在同樣的條件下,同一請求的多次執(zhí)行所產(chǎn)生的效果都是相同的。在實際開發(fā)中,為了防止重復提交或者重復操作帶來的問題,我們需要考慮如何實現(xiàn)接口冪等性。

曲松ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!

下面我將介紹如何在 SpringBoot + MySQL + MybatisPlus + Druid 的環(huán)境下實現(xiàn)接口冪等性。

  1. 什么是接口冪等性?

接口冪等性是指,對于相同的輸入,接口的輸出結(jié)果應該相同。換句話說,如果接口已經(jīng)處理了一個請求并返回了結(jié)果,那么在相同的輸入條件下,該接口的后續(xù)請求應該返回相同的結(jié)果,而不會產(chǎn)生任何新的副作用。

  1. 如何實現(xiàn)接口冪等性?

要實現(xiàn)接口冪等性,需要考慮以下幾個方面:

  • 請求唯一標識:每個請求都應該有一個唯一的標識,可以是請求參數(shù)的組合或者是一個單獨的參數(shù)。
  • 冪等性校驗:每次請求到達服務器時,服務器需要判斷該請求是否已經(jīng)被處理過,如果已經(jīng)被處理過,則直接返回處理結(jié)果,否則執(zhí)行請求操作,并記錄請求的唯一標識,以便后續(xù)的冪等性校驗。

在 SpringBoot + MySQL + MybatisPlus + Druid 的環(huán)境下,我們可以通過以下方式實現(xiàn)接口冪等性:

  • 在請求參數(shù)中添加一個冪等性校驗碼(比如 UUID),用于唯一標識每個請求。
  • 在請求處理前,先查詢冪等性校驗碼是否已經(jīng)存在于數(shù)據(jù)庫中,如果存在則說明該請求已經(jīng)被處理過,直接返回結(jié)果。
  • 如果冪等性校驗碼不存在于數(shù)據(jù)庫中,則執(zhí)行請求操作,并將冪等性校驗碼插入到數(shù)據(jù)庫中。

下面是實現(xiàn)接口冪等性的示例代碼:

在請求參數(shù)中添加一個冪等性校驗碼:

public class RequestDTO {
private String idempotenceKey;
// other request fields and methods
}

在 MybatisPlus 中創(chuàng)建對應的實體類:

@Data
@TableName("idempotence_key")
public class IdempotenceKey {
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String key;
private Date createTime;
}

在 Controller 中實現(xiàn)冪等性校驗:

@RestController
public class UserController {
@Autowired
private UserService userService;

@PostMapping("/user")
public String createUser(@RequestBody RequestDTO request) {
// 冪等性校驗
if (checkIdempotence(request.getIdempotenceKey())) {
return "success";
}
// 執(zhí)行請求操作
userService.createUser(request);
// 插入冪等性校驗碼
saveIdempotence(request.getIdempotenceKey());
return "success";
}
}

在 Service 中實現(xiàn)冪等性校驗和插入冪等性校驗碼:

@Service
public class UserService {
@Autowired
private IdempotenceKeyMapper idempotenceKeyMapper;

public void createUser(RequestDTO request) {
// 創(chuàng)建用戶
// ...
}

private boolean checkIdempotence(String key) {
IdempotenceKey idempotenceKey = idempotenceKeyMapper.selectOne(new LambdaQueryWrapper().eq(IdempotenceKey::getKey, key));
return idempotenceKey != null;
}

private void saveIdempotence(String key) {
IdempotenceKey idempotenceKey = new IdempotenceKey();
idempotenceKey.setKey(key);
idempotenceKey.setCreateTime(new Date());
idempotenceKeyMapper.insert(idempotenceKey);
}
}

這里使用了 MybatisPlus 的 LambdaQueryWrapper 進行查詢,并使用自動生成的 UUID 作為冪等性校驗碼。

全局實現(xiàn)冪等性校驗可以使用AOP(面向切面編程)來實現(xiàn),在方法執(zhí)行前先進行冪等性校驗,如果已經(jīng)執(zhí)行過該方法,則直接返回結(jié)果。可以通過自定義注解來標記需要進行冪等性校驗的方法。

以下是一個簡單的示例代碼:

  1. 自定義注解 Idempotent:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
long expireSeconds() default 60;
}
  1. 編寫 AOP 切面,用于攔截帶有 @Idempotent 注解的方法:
@Aspect
@Component
public class IdempotentAspect {
@Autowired
private IdempotenceKeyMapper idempotenceKeyMapper;

@Pointcut("@annotation(com.example.demo.annotation.Idempotent)")
public void idempotentPointcut() {}

@Around("idempotentPointcut()")
public Object idempotentAround(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Idempotent idempotent = method.getAnnotation(Idempotent.class);
String key = getKey(point);

if (StringUtils.isBlank(key)) {
throw new RuntimeException("冪等性校驗碼不能為空");
}

if (checkIdempotence(key)) {
throw new RuntimeException("請勿重復操作");
}

saveIdempotence(key, idempotent.expireSeconds());
return point.proceed();
}

private boolean checkIdempotence(String key) {
IdempotenceKey idempotenceKey = idempotenceKeyMapper.selectOne(new LambdaQueryWrapper().eq(IdempotenceKey::getKey, key));
return idempotenceKey != null;
}

private void saveIdempotence(String key, long expireSeconds) {
IdempotenceKey idempotenceKey = new IdempotenceKey();
idempotenceKey.setKey(key);
idempotenceKey.setCreateTime(new Date());
idempotenceKey.setExpireTime(new Date(System.currentTimeMillis() + expireSeconds * 1000));
idempotenceKeyMapper.insert(idempotenceKey);
}

private String getKey(ProceedingJoinPoint point) {
Object[] args = point.getArgs();
if (args.length == 0) {
return null;
}
return args[0].toString();
}
}
  1. 在需要進行冪等性校驗的方法上添加 @Idempotent 注解:
@Service
public class UserService {
@Autowired
private IdempotenceKeyMapper idempotenceKeyMapper;

@Idempotent(expireSeconds = 60)
public void createUser(String username) {
// 創(chuàng)建用戶
// ...
}
}

通過以上方式,在方法執(zhí)行前會先進行冪等性校驗,如果已經(jīng)執(zhí)行過該方法,則直接返回結(jié)果,不會再次執(zhí)行。

在實際應用中,需要考慮一些特殊情況的處理,以提高冪等性校驗的準確性和可靠性。下面列舉一些可能遇到的情況:

  1. 請求超時處理:由于冪等性校驗碼是有過期時間的,如果客戶端發(fā)起的請求在冪等性校驗碼過期后才到達服務器,那么該請求就不應該再被視為重復請求。為了解決這個問題,可以在冪等性校驗碼表中記錄請求的時間戳,并在校驗冪等性校驗碼時進行時間戳比較,以判斷請求是否超時。

在冪等性校驗碼表中添加一個請求時間戳的字段,將請求時間戳一并存儲,以便在校驗冪等性校驗碼時進行時間戳比較。

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 '創(chuàng)建時間',
`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;

// 將冪等性校驗碼和請求時間戳存入數(shù)據(jù)庫中
idempotentKeyDao.insert(key, expireTime, requestTime);

// 判斷請求是否過期
LocalDateTime threshold = now.minusMinutes(5);
if (requestTime.isBefore(threshold)) {
// 請求已經(jīng)過期,不再進行冪等性校驗
return;
}

// 進行冪等性校驗
boolean success = idempotentKeyDao.checkAndUpdate(key);
if (!success) {
// 冪等性校驗失敗
return;
}

// 執(zhí)行業(yè)務操作
// ...
}
  1. 高并發(fā)下的冪等性校驗:在高并發(fā)場景下,多個請求可能同時到達服務器進行冪等性校驗,這時需要保證校驗的準確性和唯一性??梢酝ㄟ^對冪等性校驗碼進行唯一索引的方式來保證每個冪等性校驗碼只會出現(xiàn)一次,避免多個請求同時通過校驗。

在冪等性校驗碼表的 key 字段上添加唯一索引,以保證每個冪等性校驗碼只會出現(xiàn)一次。

ALTER TABLE `idempotent_key` ADD UNIQUE INDEX `uk_key` (`key`);

在進行冪等性校驗時,需要使用數(shù)據(jù)庫的唯一索引進行校驗。

public boolean checkAndUpdate(String key) {
// 利用數(shù)據(jù)庫的唯一索引保證冪等性校驗碼的唯一性
int affectedRows = jdbcTemplate.update(
"UPDATE idempotent_key SET request_count = request_count + 1 WHERE key = ?",
key);
return affectedRows == 1;
}
  1. 冪等性校驗碼的重復利用:在一些場景下,比如一個請求執(zhí)行失敗需要重試,或者用戶進行了一些撤銷操作后需要再次執(zhí)行該操作等,冪等性校驗碼可能會被多次使用。為了避免重復利用同一個冪等性校驗碼導致的校驗失效,可以對冪等性校驗碼進行標記,標記該校驗碼已被使用過,避免再次使用。

在冪等性校驗碼表中添加一個 used 字段,標記該冪等性校驗碼是否已被使用過。

在進行冪等性校驗時,需要判斷該冪等性校驗碼是否已經(jīng)被使用過,如果已經(jīng)被使用過,則不再進行校驗。

public boolean checkAndUpdate(String key) {
// 判斷冪等性校驗碼是否已經(jīng)被使用過
boolean used = jdbcTemplate.queryForObject(
"SELECT used FROM idempotent_key WHERE key = ?",
Boolean.class,
key);
if (used) {
// 冪等性校驗碼已經(jīng)被使用過,不再進行校驗
return true;
}

// 將冪等性校驗碼標記為已使用
int affectedRows = jdbcTemplate.update(
"UPDATE idempotent_key SET used = true WHERE key = ?",
key);
return affectedRows == 1;
}
  1. 冪等性校驗碼的生成規(guī)則:冪等性校驗碼的生成規(guī)則也需要考慮,應該根據(jù)業(yè)務的特點來確定??梢圆捎秒S機數(shù)、UUID、請求參數(shù)哈希等方式生成冪等性校驗碼。需要保證冪等性校驗碼在相同的請求條件下生成的結(jié)果一致。

在分布式環(huán)境下,需要保證不同實例之間共享冪等性校驗碼的狀態(tài)??梢允褂?Redis 等分布式緩存來存儲冪等性校驗碼狀態(tài)。

public boolean checkAndUpdate(String key) {
// 從 Redis 中獲取冪等性校驗碼的狀態(tài)
boolean used = redisTemplate.opsForValue().get(key);
if (used) {
// 冪等性校驗碼已經(jīng)被使用過,不再進行校驗
return true;
}

// 將冪等性校驗碼標記為已使用
redisTemplate.opsForValue().set(key, true);

// 執(zhí)行業(yè)務操作
// ...

return true;
}

需要注意的是,由于 Redis 中存儲的數(shù)據(jù)可能會被意外刪除或過期,因此在使用 Redis 作為冪等性校驗碼狀態(tài)存儲介質(zhì)時,需要考慮數(shù)據(jù)丟失或過期的情況,確保系統(tǒng)的可靠性和正確性。


文章題目:在分布式系統(tǒng)中,SpringBoot實現(xiàn)接口冪等性
文章起源:http://www.5511xx.com/article/dpsedgo.html