国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

目次
7. テスト検証 " >7. テスト検証
ホームページ Java &#&面接の質(zhì)問 インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。

インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。

Aug 22, 2023 pm 03:57 PM
Javaの面接の質(zhì)問

#皆さん、こんにちは。私はティアン兄弟です。

昨日、私は ## をしていました。友人 # 模擬面接、インターフェイス冪等性を?qū)g裝するにはどうすればよいですか?彼の答えの口調(diào)から、彼が 8 部構(gòu)成のエッセイを暗記していることがわかります。 そこで、インターフェースの冪等実裝を誰もが簡単に體験できるように、Tian 兄弟 は今日この記事を手配しました 。

この記事には 9 つの主要な內(nèi)容があります:

1. 電力コンセプト等価性 インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。

# 冪等性は、平たく言えばインターフェイスです。同じリクエストを複數(shù)回開始する場合は、その操作が 1 回しか実行できないことを確認(rèn)する必要があります。たとえば、 :
  • #注文インターフェイス、注文は複數(shù)回作成できません
  • 支払いインターフェイス、同じ注文の支払いは 1 回のみ引き落とし可能
  • Alipay コールバック インターフェイス、複數(shù)のコールバックが存在する可能性があり、繰り返されるコールバックは処理する必要があります
  • 通常のフォーム送信インターフェイス、ネットワーク タイムアウトやその他の理由により、クリックすることしかできません複數(shù)回送信しても成功できるのは 1 回だけです。お待??ちください

2. 一般的な解決策

  1. 一意のインデックス -- 新しいダーティ データを防止します
  2. トークン メカニズム -- ページの繰り返し送信を防止します
  3. 悲観的ロック-- データ取得時にロックします(テーブルまたは行をロック)
  4. #楽観的ロック--バージョン番號に基づいて実裝され、データが更新された時點でデータを検証します
  5. 分散ロック -- redis (jedis、redisson) または Zookeeper の実裝
  6. ステート マシン -- 狀態(tài)変更、データ更新時の狀態(tài)の決定

3. この記事の実裝 この記事では 2 番目の方法を使用して実裝します。

Redis トークン

メカニズムは、インターフェイスの冪等性チェックを?qū)g現(xiàn)します。 <h2 data-tool="mdnice編輯器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"> <span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">4. 実裝のアイデア</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span> </h2> <p data-tool="mdnice編輯器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 1px;margin-bottom: 1px;">冪等性を確保する必要があるリクエストごとに一意の識別子を作成します <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">token 、まず token を取得し、この token を redis に保存します。インターフェイスをリクエストするときは、この token をヘッダーに置くか、インターフェイスをリクエストするためのリクエスト パラメーターとして入れます。バックエンド インターフェイスは、この token:

が Redis に存在するかどうかを判斷します。
  • 存在する場合は、ビジネス ロジックを通常どおり処理し、この token を redis から削除します。その後、繰り返しのリクエストである場合は、token が既に削除されているため、削除されました。検証に合格できず、操作を繰り返さないでくださいを返しますプロンプト
  • これが存在しない場合は、パラメータが不正であるか、リクエストが無効であることを意味します。繰り返し、プロンプトを返すだけです

5. プロジェクトの紹介

  • Spring Boot
  • Redis
  • ##@ApiIdempotentアノテーション インターセプターリクエストをインターセプト
  • @ControllerAdviceグローバル例外処理
  • #ストレス テスト ツール:
  • Jmeter
  • 注:

この記事はべき等性のコア実裝に焦點を當(dāng)てています。Spring Boot が Redis、ServerResponse、ResponseCode をどのように統(tǒng)合するか、およびその他の詳細(xì)については範(fàn)囲を超えています。この記事の內(nèi)容。

6. コードの実裝

1, maven依存関係

<!-- Redis-Jedis -->
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>2.9.0</version>
</dependency>

<!--lombok 本文用到@Slf4j注解, 也可不引用, 自定義log即可-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.10</version>
</dependency>

2. JedisUtil

@Component
@Slf4j
public class JedisUtil {

    @Autowired
    private JedisPool jedisPool;

    private Jedis getJedis() {
        return jedisPool.getResource();
    }

    /**
     * 設(shè)值
     *
     * @param key
     * @param value
     * @return
     */
    public String set(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.set(key, value);
        } catch (Exception e) {
            log.error("set key:{} value:{} error", key, value, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 設(shè)值
     *
     * @param key
     * @param value
     * @param expireTime 過期時間, 單位: s
     * @return
     */
    public String set(String key, String value, int expireTime) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.setex(key, expireTime, value);
        } catch (Exception e) {
            log.error("set key:{} value:{} expireTime:{} error", key, value, expireTime, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 取值
     *
     * @param key
     * @return
     */
    public String get(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.get(key);
        } catch (Exception e) {
            log.error("get key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 刪除key
     *
     * @param key
     * @return
     */
    public Long del(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.del(key.getBytes());
        } catch (Exception e) {
            log.error("del key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 判斷key是否存在
     *
     * @param key
     * @return
     */
    public Boolean exists(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.exists(key.getBytes());
        } catch (Exception e) {
            log.error("exists key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 設(shè)值key過期時間
     *
     * @param key
     * @param expireTime 過期時間, 單位: s
     * @return
     */
    public Long expire(String key, int expireTime) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.expire(key.getBytes(), expireTime);
        } catch (Exception e) {
            log.error("expire key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    /**
     * 獲取剩余時間
     *
     * @param key
     * @return
     */
    public Long ttl(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            return jedis.ttl(key);
        } catch (Exception e) {
            log.error("ttl key:{} error", key, e);
            return null;
        } finally {
            close(jedis);
        }
    }

    private void close(Jedis jedis) {
        if (null != jedis) {
            jedis.close();
        }
    }

}

3. カスタム アノテーション @ApiIdempotent

/**
 * 在需要保證 接口冪等性 的Controller的方法上使用此注解
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiIdempotent {
}

4. ApiIdempotentInterceptor インターセプター

/**
 * 接口冪等性攔截器
 */
public class ApiIdempotentInterceptor implements HandlerInterceptor {

    @Autowired
    private TokenService tokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        ApiIdempotent methodAnnotation = method.getAnnotation(ApiIdempotent.class);
        if (methodAnnotation != null) {
            check(request);// 冪等性校驗, 校驗通過則放行, 校驗失敗則拋出異常, 并通過統(tǒng)一異常處理返回友好提示
        }

        return true;
    }

    private void check(HttpServletRequest request) {
        tokenService.checkToken(request);
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    }
}

5、TokenServiceImpl

@Service
public class TokenServiceImpl implements TokenService {

    private static final String TOKEN_NAME = "token";

    @Autowired
    private JedisUtil jedisUtil;

    @Override
    public ServerResponse createToken() {
        String str = RandomUtil.UUID32();
        StrBuilder token = new StrBuilder();
        token.append(Constant.Redis.TOKEN_PREFIX).append(str);

        jedisUtil.set(token.toString(), token.toString(), Constant.Redis.EXPIRE_TIME_MINUTE);

        return ServerResponse.success(token.toString());
    }

    @Override
    public void checkToken(HttpServletRequest request) {
        String token = request.getHeader(TOKEN_NAME);
        if (StringUtils.isBlank(token)) {// header中不存在token
            token = request.getParameter(TOKEN_NAME);
            if (StringUtils.isBlank(token)) {// parameter中也不存在token
                throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getMsg());
            }
        }

        if (!jedisUtil.exists(token)) {
            throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg());
        }

        Long del = jedisUtil.del(token);
        if (del <= 0) {
            throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg());
        }
    }

}

6、TestApplication

@SpringBootApplication
@MapperScan("com.wangzaiplus.test.mapper")
public class TestApplication  extends WebMvcConfigurerAdapter {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

    /**
     * 跨域
     * @return
     */
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 接口冪等性攔截器
        registry.addInterceptor(apiIdempotentInterceptor());
        super.addInterceptors(registry);
    }

    @Bean
    public ApiIdempotentInterceptor apiIdempotentInterceptor() {
        return new ApiIdempotentInterceptor();
    }

}

さて、上記はコードの実裝部分です。それを確認(rèn)してください。

7. テスト検証

tokenTokenController# のコントローラーを取得します。 ##:

@RestController
@RequestMapping("/token")
public class TokenController {

    @Autowired
    private TokenService tokenService;

    @GetMapping
    public ServerResponse token() {
        return tokenService.createToken();
    }

}

TestController, 注意@ApiIdempotent注解, 在需要冪等性校驗的方法上聲明此注解即可, 不需要校驗的無影響:

@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {

    @Autowired
    private TestService testService;

    @ApiIdempotent
    @PostMapping("testIdempotence")
    public ServerResponse testIdempotence() {
        return testService.testIdempotence();
    }

}

獲取token

インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。

查看Redis

インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。

測試接口安全性: 利用Jmeter測試工具模擬50個并發(fā)請求, 將上一步獲取到的token作為參數(shù)

インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。
インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。

header或參數(shù)均不傳token, 或者token值為空, 或者token值亂填, 均無法通過校驗, 如token值為abcd

インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。

8. 注意事項 (非常に重要)

インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。
# # 上の図では、削除が成功したかどうかを確認(rèn)せずにトークンを直接削除することはできません。複數(shù)のスレッドが同時に 46 行目に達(dá)する可能性があり、この時點ではトークンが削除されていないため、同時実行性のセキュリティの問題が発生します。

jedisUtil.del(token) の削除結(jié)果を確認(rèn)せずに直接解放すると、実際の削除操作が 1 つだけであっても、重複送信の問題が依然として発生します。 、以下を 1 回再現(xiàn)します。

コードを少し変更します:

インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。
もう一度リクエストします

インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。
コンソールをもう一度見てください

インタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。
実際に削除されるのは 1 つのトークンだけですが、削除結(jié)果の検証が行われていないため、同時実行性の問題が依然として殘っているため、検証が必要です。

9. 概要

実際、考え方は非常にシンプルで、各リクエストが一意であることが保証されています。これにより、interceptor アノテーション を介して 冪等性プロパティ が保証され、リクエストごとに繰り返しコードを記述する必要がなくなります。実際、Spring AOP## を使用して実裝することもできます。 #。

わかりました。今日はここで共有します。 ##################################

以上がインタビュアー: 支払いインターフェースでは、同じ注文に対する繰り返しの支払いに対して、金額を差し引くことができるのは 1 回だけです。の詳細(xì)內(nèi)容です。詳細(xì)については、PHP 中國語 Web サイトの他の関連記事を參照してください。

このウェブサイトの聲明
この記事の內(nèi)容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰屬します。このサイトは、それに相當(dāng)する法的責(zé)任を負(fù)いません。盜作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡(luò)ください。

ホットAIツール

Undress AI Tool

Undress AI Tool

脫衣畫像を無料で

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード寫真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

寫真から衣服を削除するオンライン AI ツール。

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中國語版

SublimeText3 中國語版

中國語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統(tǒng)合開発環(huán)境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

インタビュアー: Spring Aop の共通アノテーションと実行シーケンス インタビュアー: Spring Aop の共通アノテーションと実行シーケンス Aug 15, 2023 pm 04:32 PM

Spring について知っている必要があるので、Aop のすべての通知の順序について話しましょう。Spring Boot または Spring Boot 2 は AOP の実行順序にどのように影響しますか? AOP で遭遇した落とし穴について教えてください。

特定のグループへのインタビュー: オンラインで OOM に遭遇した場合、どのようにトラブルシューティングを行うべきですか?の解き方?どのようなオプションがありますか? 特定のグループへのインタビュー: オンラインで OOM に遭遇した場合、どのようにトラブルシューティングを行うべきですか?の解き方?どのようなオプションがありますか? Aug 23, 2023 pm 02:34 PM

OOM は、プログラムに脆弱性があることを意味します。これは、コードまたは JVM パラメータ設(shè)定が原因である可能性があります。この記事では、Java プロセスが OOM をトリガーした場合のトラブルシューティング方法について読者に説明します。

Ele.me の筆記試験問題は簡単そうに見えますが、多くの人が困惑します。 Ele.me の筆記試験問題は簡単そうに見えますが、多くの人が困惑します。 Aug 24, 2023 pm 03:29 PM

多くの企業(yè)の筆記試験の問題には落とし穴があり、うっかり陥る可能性がありますので、甘く見ないでください。サイクルに関するこの種の筆記試験問題に遭遇した場合は、冷靜に考えて段階的に解答することをお勧めします。

先週、XX保険の面接を受けましたが、とても良かったです。 ! ! 先週、XX保険の面接を受けましたが、とても良かったです。 ! ! Aug 25, 2023 pm 03:44 PM

「先週、グループの友人が平安保険の面接に行きました。結(jié)果は少し殘念でした。非常に殘念ですが、落ち込まないでほしいと思います。あなたが言ったように、基本的には、ここで出た質(zhì)問はすべて解決しました」面接は面接の質(zhì)問を暗記すれば解けますので、頑張ってください!

面接での 5 つの質(zhì)問。すべてに正解できる人は 10% 未満です。 (答え付き) 面接での 5 つの質(zhì)問。すべてに正解できる人は 10% 未満です。 (答え付き) Aug 23, 2023 pm 02:49 PM

この記事では、Java String クラスに関する 5 つの面接の質(zhì)問を取り上げます。私は面接プロセス中にこれら 5 つの質(zhì)問のうちのいくつかを個人的に経験しました。この記事は、これらの質(zhì)問に対する答えがなぜこのようになるのかを理解するのに役立ちます。

初心者も BAT 面接官と競爭できる: CAS 初心者も BAT 面接官と競爭できる: CAS Aug 24, 2023 pm 03:09 PM

Java並行プログラミングシリーズの番外編「C A S (Compare and swap)」は、絵と文章でわかりやすく、インタビュアーと夢中で會話できるスタイルを保っています。

ほぼすべての Java インタビューで聞かれる質(zhì)問: ArrayList と LinkedList の違いについての話 ほぼすべての Java インタビューで聞かれる質(zhì)問: ArrayList と LinkedList の違いについての話 Jul 26, 2023 pm 03:11 PM

Java のデータ構(gòu)造がインタビューの焦點です。Java のインタビューに參加したことのある人なら誰でも、ある程度の経験があるはずです。面接官がこのような質(zhì)問をするとき、単に「使い方を知っている」というレベルにとどまるのではなく、Java で一般的に使用されるデータ型の基礎(chǔ)となる構(gòu)造を?qū)W習(xí)したかどうかを確認(rèn)したいことがよくあります。

インタビュアー: クラスロードプロセスについて教えてください (10 個の図) インタビュアー: クラスロードプロセスについて教えてください (10 個の図) Aug 23, 2023 pm 03:05 PM

クラスを使用する場合は、ClassLoader を通じてクラスをメモリにロードする必要があります。

See all articles