偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

在分布式系統(tǒng)中,SpringBoot 實(shí)現(xiàn)接口冪等性

開發(fā) 架構(gòu)
下面我將介紹如何在 SpringBoot + MySQL + MybatisPlus + Druid 的環(huán)境下實(shí)現(xiàn)接口冪等性。

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

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

  1. 什么是接口冪等性?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

在 Service 中實(shí)現(xiàn)冪等性校驗(yàn)和插入冪等性校驗(yà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<IdempotenceKey>().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 進(jìn)行查詢,并使用自動生成的 UUID 作為冪等性校驗(yàn)碼。

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

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

  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("冪等性校驗(yàn)碼不能為空");
}

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

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

private boolean checkIdempotence(String key) {
IdempotenceKey idempotenceKey = idempotenceKeyMapper.selectOne(new LambdaQueryWrapper<IdempotenceKey>().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. 在需要進(jìn)行冪等性校驗(yàn)的方法上添加 @Idempotent 注解:
@Service
public class UserService {
@Autowired
private IdempotenceKeyMapper idempotenceKeyMapper;

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

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

在實(shí)際應(yīng)用中,需要考慮一些特殊情況的處理,以提高冪等性校驗(yàn)的準(zhǔn)確性和可靠性。下面列舉一些可能遇到的情況:

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

在冪等性校驗(yàn)碼表中添加一個請求時(shí)間戳的字段,將請求時(shí)間戳一并存儲,以便在校驗(yàn)冪等性校驗(yàn)碼時(shí)進(jìn)行時(shí)間戳比較。

CREATE TABLE `idempotent_key` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`key` varchar(128) NOT NULL COMMENT '冪等性校驗(yàn)碼',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
`expire_time` datetime NOT NULL COMMENT '過期時(shí)間',
`request_time` datetime NOT NULL COMMENT '請求時(shí)間',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_key` (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='冪等性校驗(yàn)碼表';

在進(jìn)行冪等性校驗(yàn)時(shí),需要先判斷冪等性校驗(yàn)碼是否過期,如果過期則不再進(jìn)行校驗(yàn)。

public void processRequest() {
String key = generateIdempotentKey();
LocalDateTime now = LocalDateTime.now();
LocalDateTime expireTime = now.plusMinutes(5);
LocalDateTime requestTime = now;

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

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

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

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

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

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

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

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

在冪等性校驗(yàn)碼表中添加一個 used 字段,標(biāo)記該冪等性校驗(yàn)碼是否已被使用過。

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

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

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

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

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

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

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

return true;
}

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

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2021-01-13 11:23:59

分布式冪等性支付

2024-07-03 11:59:40

2025-02-14 14:22:40

2023-10-26 07:32:42

2023-01-13 07:39:07

2024-03-13 15:18:00

接口冪等性高并發(fā)

2021-12-01 10:13:48

場景分布式并發(fā)

2013-08-09 09:27:31

2021-01-18 14:34:59

冪等性接口客戶端

2022-01-12 09:01:24

分布式系統(tǒng)容錯服務(wù)

2025-02-23 08:00:00

冪等性Java開發(fā)

2024-01-31 09:54:51

Redis分布式

2024-06-03 14:17:00

2023-05-29 14:07:00

Zuul網(wǎng)關(guān)系統(tǒng)

2021-07-28 08:39:25

分布式架構(gòu)系統(tǒng)

2024-06-24 01:00:00

2023-05-12 08:23:03

分布式系統(tǒng)網(wǎng)絡(luò)

2024-08-29 09:01:39

2023-11-01 08:54:22

冪等性Python

2024-11-01 09:28:02

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號