chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一個注解,優(yōu)雅的實現(xiàn)接口冪等性!

jf_ro2CN3Fa ? 來源:芋道源碼 ? 2023-08-26 14:36 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群


一、什么是冪等性?

簡單來說,就是對一個接口執(zhí)行重復的多次請求,與一次請求所產生的結果是相同的,聽起來非常容易理解,但要真正的在系統(tǒng)中要始終保持這個目標,是需要很嚴謹?shù)脑O計的,在實際的生產環(huán)境下,我們應該保證任何接口都是冪等的,而如何正確的實現(xiàn)冪等,就是本文要討論的內容。

基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權限、多租戶、數(shù)據(jù)權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

二、哪些請求天生就是冪等的?

首先,我們要知道查詢類的請求一般都是天然冪等的,除此之外,刪除請求在大多數(shù)情況下也是冪等的,但是ABA場景下除外。

舉一個簡單的例子

比如,先請求了一次刪除A的操作,但由于響應超時,又自動請求了一次刪除A的操作,如果在兩次請求之間,又插入了一次A,而實際上新插入的這一次A,是不應該被刪除的,這就是ABA問題,不過,在大多數(shù)業(yè)務場景中,ABA問題都是可以忽略的。

除了查詢和刪除之外,還有更新操作,同樣的更新操作在大多數(shù)場景下也是天然冪等的,其例外是也會存在ABA的問題,更重要的是,比如執(zhí)行update table set a = a + 1 where v = 1這樣的更新就非冪等了。

最后,就還剩插入了,插入大多數(shù)情況下都是非冪等的,除非是利用數(shù)據(jù)庫唯一索引來保證數(shù)據(jù)不會重復產生。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權限、多租戶、數(shù)據(jù)權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

三、為什么需要冪等

1.超時重試

當發(fā)起一次RPC請求時,難免會因為網絡不穩(wěn)定而導致請求失敗,一般遇到這樣的問題我們希望能夠重新請求一次,正常情況下沒有問題,但有時請求實際上已經發(fā)出去了,只是在請求響應時網絡異?;蛘叱瑫r,此時,請求方如果再重新發(fā)起一次請求,那被請求方就需要保證冪等了。

2.異步回調

異步回調是提升系統(tǒng)接口吞吐量的一種常用方式,很明顯,此類接口一定是需要保證冪等性的。

3.消息隊列

現(xiàn)在常用的消息隊列框架,比如:Kafka、RocketMQ、RabbitMQ在消息傳遞時都會采取At least once原則(也就是至少一次原則,在消息傳遞時,不允許丟消息,但是允許有重復的消息),既然消息隊列不保證不會出現(xiàn)重復的消息,那消費者自然要保證處理邏輯的冪等性了。

四、實現(xiàn)冪等的關鍵因素

關鍵因素1

冪等唯一標識,可以叫它冪等號或者冪等令牌或者全局ID,總之就是客戶端與服務端一次請求時的唯一標識,一般情況下由客戶端來生成,也可以讓第三方來統(tǒng)一分配。

關鍵因素2

有了唯一標識以后,服務端只需要確保這個唯一標識只被使用一次即可,一種常見的方式就是利用數(shù)據(jù)庫的唯一索引。

五、注解實現(xiàn)冪等性

下面演示一種利用Redis來實現(xiàn)的方式。

1.自定義注解

importjava.lang.annotation.ElementType;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;

@Target(value=ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public@interfaceIdempotent{

/**
*參數(shù)名,表示將從哪個參數(shù)中獲取屬性值。
*獲取到的屬性值將作為KEY。
*
*@return
*/
Stringname()default"";

/**
*屬性,表示將獲取哪個屬性的值。
*
*@return
*/
Stringfield()default"";

/**
*參數(shù)類型
*
*@return
*/
Classtype();

}

2.統(tǒng)一的請求入?yún)ο?/h4>
@Data
publicclassRequestData<T>{

privateHeaderheader;

privateTbody;

}


@Data
publicclassHeader{

privateStringtoken;

}

@Data
publicclassOrder{

StringorderNo;

}

3.AOP處理

importcom.springboot.micrometer.annotation.Idempotent;
importcom.springboot.micrometer.entity.RequestData;
importcom.springboot.micrometer.idempotent.RedisIdempotentStorage;
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.annotation.Around;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Pointcut;
importorg.aspectj.lang.reflect.MethodSignature;
importorg.springframework.stereotype.Component;

importjavax.annotation.Resource;
importjava.lang.reflect.Method;
importjava.util.Map;

@Aspect
@Component
publicclassIdempotentAspect{

@Resource
privateRedisIdempotentStorageredisIdempotentStorage;

@Pointcut("@annotation(com.springboot.micrometer.annotation.Idempotent)")
publicvoididempotent(){
}

@Around("idempotent()")
publicObjectmethodAround(ProceedingJoinPointjoinPoint)throwsThrowable{
MethodSignaturesignature=(MethodSignature)joinPoint.getSignature();
Methodmethod=signature.getMethod();
Idempotentidempotent=method.getAnnotation(Idempotent.class);

Stringfield=idempotent.field();
Stringname=idempotent.name();
ClassclazzType=idempotent.type();

Stringtoken="";

Objectobject=clazzType.newInstance();
MapparamValue=AopUtils.getParamValue(joinPoint);
if(objectinstanceofRequestData){
RequestDataidempotentEntity=(RequestData)paramValue.get(name);
token=String.valueOf(AopUtils.getFieldValue(idempotentEntity.getHeader(),field));
}

if(redisIdempotentStorage.delete(token)){
returnjoinPoint.proceed();
}
return"重復請求";
}
}
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.reflect.CodeSignature;

importjava.lang.reflect.Field;
importjava.util.HashMap;
importjava.util.Map;

publicclassAopUtils{

publicstaticObjectgetFieldValue(Objectobj,Stringname)throwsException{
Field[]fields=obj.getClass().getDeclaredFields();
Objectobject=null;
for(Fieldfield:fields){
field.setAccessible(true);
if(field.getName().toUpperCase().equals(name.toUpperCase())){
object=field.get(obj);
break;
}
}
returnobject;
}


publicstaticMapgetParamValue(ProceedingJoinPointjoinPoint){
Object[]paramValues=joinPoint.getArgs();
String[]paramNames=((CodeSignature)joinPoint.getSignature()).getParameterNames();
Mapparam=newHashMap<>(paramNames.length);

for(inti=0;ireturnparam;
}
}

4.Token值生成

importcom.springboot.micrometer.idempotent.RedisIdempotentStorage;
importcom.springboot.micrometer.util.IdGeneratorUtil;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;

importjavax.annotation.Resource;

@RestController
@RequestMapping("/idGenerator")
publicclassIdGeneratorController{

@Resource
privateRedisIdempotentStorageredisIdempotentStorage;

@RequestMapping("/getIdGeneratorToken")
publicStringgetIdGeneratorToken(){
StringgenerateId=IdGeneratorUtil.generateId();
redisIdempotentStorage.save(generateId);
returngenerateId;
}

}
publicinterfaceIdempotentStorage{

voidsave(StringidempotentId);

booleandelete(StringidempotentId);
}
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.stereotype.Component;

importjavax.annotation.Resource;
importjava.io.Serializable;
importjava.util.concurrent.TimeUnit;

@Component
publicclassRedisIdempotentStorageimplementsIdempotentStorage{

@Resource
privateRedisTemplateredisTemplate;

@Override
publicvoidsave(StringidempotentId){
redisTemplate.opsForValue().set(idempotentId,idempotentId,10,TimeUnit.MINUTES);
}

@Override
publicbooleandelete(StringidempotentId){
returnredisTemplate.delete(idempotentId);
}
}
importjava.util.UUID;

publicclassIdGeneratorUtil{

publicstaticStringgenerateId(){
returnUUID.randomUUID().toString();
}

}

5. 請求示例

調用接口之前,先申請一個token,然后帶著服務端返回的token值,再去請求。

importcom.springboot.micrometer.annotation.Idempotent;
importcom.springboot.micrometer.entity.Order;
importcom.springboot.micrometer.entity.RequestData;
importorg.springframework.web.bind.annotation.RequestBody;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/order")
publicclassOrderController{

@RequestMapping("/saveOrder")
@Idempotent(name="requestData",type=RequestData.class,field="token")
publicStringsaveOrder(@RequestBodyRequestDatarequestData){
return"success";
}

}

請求獲取token值。

533d7310-43cc-11ee-a2ef-92fbcf53809c.png

帶著token值,第一次請求成功。

53540ddc-43cc-11ee-a2ef-92fbcf53809c.png

第二次請求失敗。

53676bde-43cc-11ee-a2ef-92fbcf53809c.png


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    9275

    瀏覽量

    155487
  • RPC
    RPC
    +關注

    關注

    0

    文章

    113

    瀏覽量

    12112
  • 管理系統(tǒng)

    關注

    1

    文章

    2848

    瀏覽量

    38051

原文標題:一個注解,優(yōu)雅的實現(xiàn)接口冪等性!

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    離線計算中的和DataWorks中的相關事項

    多次相同的消息,針對同筆交易的付款也不應該在重試過程中扣多次錢。曾見過案例,有對于
    發(fā)表于 02-27 13:24

    在高并發(fā)下怎么保證接口?

    前言 接口性問題,對于開發(fā)人員來說,是跟語言無關的公共問題。本文分享了些解決這類問題非
    的頭像 發(fā)表于 05-14 10:23 ?2171次閱讀
    在高并發(fā)下怎么保證<b class='flag-5'>接口</b>的<b class='flag-5'>冪</b><b class='flag-5'>等</b><b class='flag-5'>性</b>?

    注解定義Bean及開發(fā)

    注解本質是繼承了Annotation 的特殊接口,其具體實現(xiàn)類是Java 運行時生成的動態(tài)代理類。
    發(fā)表于 08-02 10:26 ?623次閱讀

    什么是?關于接口的解決方案

    這里的樂觀鎖指的是用樂觀鎖的原理去實現(xiàn),為數(shù)據(jù)字段增加version字段,當數(shù)據(jù)需要更新時,先去數(shù)據(jù)庫里獲取此時的version版本號
    發(fā)表于 10-09 10:19 ?2410次閱讀

    分析解決)的方法

    這個概念,是數(shù)學上的概念,即:f……(f(f(x))) = f(x)。用在計算機領域,指的是系統(tǒng)里的接口或方法對外的
    的頭像 發(fā)表于 10-14 10:08 ?1486次閱讀

    Spring Boot實現(xiàn)接口的4種方案

    數(shù)學與計算機學概念,在數(shù)學中某元運算為
    的頭像 發(fā)表于 11-08 10:21 ?1334次閱讀

    如何設計優(yōu)雅的API接口

    種是API接口提供方給出AK/SK兩值,雙方約定用SK作為簽名中的密鑰。AK接口調用方作為header中的accessKey傳遞給API接口
    的頭像 發(fā)表于 12-20 14:23 ?2137次閱讀

    什么是?實現(xiàn)原理

    在編程中操作的特點是其任意多次執(zhí)行所產生的影響均與次執(zhí)行的影響相同。
    發(fā)表于 01-05 10:40 ?7213次閱讀

    如何實現(xiàn)注解進行數(shù)據(jù)脫敏

    、測試 后記 ? 本文主要分享什么是數(shù)據(jù)脫敏,如何優(yōu)雅的在項目中運用注解實現(xiàn)數(shù)據(jù)脫敏,為項目進行賦能。希望能給你們帶來幫助。 什么是數(shù)據(jù)
    的頭像 發(fā)表于 06-14 09:37 ?1441次閱讀
    如何<b class='flag-5'>實現(xiàn)</b><b class='flag-5'>一</b><b class='flag-5'>個</b><b class='flag-5'>注解</b>進行數(shù)據(jù)脫敏

    基于接口解決方案

    接口是指無論調用接口的次數(shù)是次還是多次,對于同
    的頭像 發(fā)表于 09-30 16:27 ?733次閱讀
    基于<b class='flag-5'>接口</b><b class='flag-5'>冪</b><b class='flag-5'>等</b><b class='flag-5'>性</b>解決方案

    和非請求的些定義和分析

    最近在做項目的過程中,有需求是在客戶端 HTTP 請求失敗后,增加重試機制,然后我就翻了些有關“重試”的庫,找到
    的頭像 發(fā)表于 10-17 10:50 ?1323次閱讀

    接口統(tǒng)異常優(yōu)雅處理介紹及實戰(zhàn)

    Spring在3.2版本增加了注解@ControllerAdvice,可以與@ExceptionHandler、@InitBinder、@ModelAttribute
    的頭像 發(fā)表于 10-22 16:01 ?1122次閱讀
    <b class='flag-5'>接口</b>統(tǒng)<b class='flag-5'>一</b>異常<b class='flag-5'>優(yōu)雅</b>處理介紹及實戰(zhàn)

    為什么要實現(xiàn)校驗 如何實現(xiàn)接口校驗

    前端重復提交表單:在填寫些表格時候,用戶填寫完成提交,很多時候會因網絡波動沒有及時對用戶做出提交成功響應,致使用戶認為沒有成功提交,然后直點提交按鈕,這時就會發(fā)生重復提交表單請求。
    的頭像 發(fā)表于 02-20 14:14 ?1858次閱讀

    探索LabVIEW編程接口原理與實踐

    原來是數(shù)學上的概念,在編程領域可以理解為:多次請求某一個資源或執(zhí)行某一個操作時應該具有唯一性
    的頭像 發(fā)表于 02-29 10:24 ?1182次閱讀
    探索LabVIEW編程<b class='flag-5'>接口</b><b class='flag-5'>冪</b><b class='flag-5'>等</b><b class='flag-5'>性</b>原理與實踐

    如何秒級實現(xiàn)接口間“”補償:款輕量級仿數(shù)據(jù)校正處理輔助工具

    導語 本文分析了在網絡超時場景下,RPC服務調用數(shù)據(jù)一致性的問題,對于接口、接口
    的頭像 發(fā)表于 09-15 16:55 ?465次閱讀
    如何秒級<b class='flag-5'>實現(xiàn)</b><b class='flag-5'>接口</b>間“<b class='flag-5'>冪</b><b class='flag-5'>等</b>”補償:<b class='flag-5'>一</b>款輕量級仿<b class='flag-5'>冪</b><b class='flag-5'>等</b>數(shù)據(jù)校正處理輔助工具