[Spring Boot] インターフェイスの冪等性を実現する 4 つの方法

[Spring Boot] インターフェイスの冪等性を実現する 4 つの方法

1.冪等性とは何ですか?

冪等とは数学とコンピュータ サイエンスの概念です。数学では、特定の要素の演算が冪等である場合、その要素に対するその効果が 2 回発生すると、1 回の効果と同じ結果が得られます。コンピューター プログラミングにおける冪等操作の特徴は、その実行が何回実行されても 1 回の実行と同じ影響を与えることです冪等関数または冪等メソッドは、同じパラメータを使用して繰り返し実行でき、同じ結果が得られる関数です。これらの関数はシステムの状態に影響を与えず、繰り返しの実行によるシステムの変化を心配する必要はありません。

2. インターフェース冪等性とは何ですか?

HTTP/1.1 では冪等性が定義されています。これは、リソースに対する 1 つまたは複数のリクエストがリソース自体に対して同じ結果をもたらす必要があることを説明しています (ネットワーク タイムアウトなどの問題を除く)。つまり、最初のリクエストはリソースに副作用をもたらしますが、後続のリクエストでは副作用が発生しません。効果: リソースに副作用がありますここでの副作用によって結果が損なわれたり、予測不可能な結果が生じることはありません。つまり、複数の実行はリソース自体に 1 回の実行と同じ影響を与えます。

3. 冪等性を達成する必要がある理由

通常の状況では、インターフェイスが呼び出されると、情報は正常に返され、繰り返し送信されることはありませんが、次のような状況が発生した場合に問題が発生する可能性があります。

  • フロントエンドでのフォームの繰り返し送信:一部のフォームに入力すると、ユーザーは送信を完了しますが、多くの場合、ネットワークの変動により、ユーザーは時間内に送信成功の応答を受信できず、ユーザーは送信が完了したと思い込んでしまいます。フォームリクエストを繰り返し送信してください。
  • ユーザーが悪意を持って不正行為を行う:たとえば、ユーザー投票機能を実装する場合、ユーザーが繰り返し投票を送信すると、インターフェイスがユーザーによって繰り返し送信された投票情報を受信することになり、投票結果が重大な影響を与える可能性があります。事実と一致しない。
  • インターフェイスのタイムアウトと繰り返し送信:多くの HTTP クライアント ツールでは、特にサードパーティがインターフェイスを呼び出す場合に、デフォルトでタイムアウト再試行メカニズムが有効になっています。ネットワークの変動やタイムアウトなどによるリクエストの失敗を防ぐために、再試行メカニズムが追加されます。その結果、1 つのリクエストが複数回送信されることになります。
  • メッセージの繰り返し消費: MQ メッセージ ミドルウェアを使用する場合、メッセージ ミドルウェアでエラーが発生し、消費情報が時間内に送信されないと、繰り返し消費が発生します。

べき等性を使用する最大の利点は、インターフェースがべき等な動作を保証し、システム内の再試行などによって引き起こされる未知の問題を回避できることです。

4.べき等性の導入後のシステムへの影響

冪等性はクライアント ロジックの処理を簡素化し、繰り返し送信などの操作を配置できますが、ロジックの複雑さとサーバーのコストが増加します。

  • 並列実行機能をシリアル実行に変更すると、実行効率が低下します。
  • 冪等性を制御するための追加のビジネス ロジックが追加され、ビジネス機能が複雑になります。

実際のビジネスシナリオを具体的に分析すると、特別なビジネス要件を除いて、一般的にインターフェース冪等性を導入する必要はありません。

5. Restful APIインターフェースの冪等性

人気のある Restful によって推奨されているいくつかの HTTP インターフェイス メソッドの中には、次のように冪等性を保証できない行やメソッドがあります。

  • √ 冪等性を満たす
  • x はべき等ではありません
  • - 実際のビジネス ロジックに応じて、冪等性を満たす場合と満たさない場合があります。
メソッドの種類 べき等ですか? 説明する
得る リソースを取得するにはGetメソッドを使用します。通常、システム リソースは変更しませんし、変更すべきではないため、冪等です。
役職 × Post メソッドは通常、新しいリソースを作成するために使用されます。実行されるたびに新しいデータが追加されるため、冪等ではありません。
置く - Put メソッドは通常、リソースを変更するために使用されます。この操作は冪等であるかどうかを状況に応じて判断するものであり、更新操作においても、ある値をもとに直接更新することで冪等性を維持することができる。ただし、蓄積操作を実行する更新はべき等ではありません。
消去 - Delete メソッドは通常、リソースを削除するために使用されます。この操作は冪等であるかどうかを状況に応じて判断するため、一意の値に基づいて削除する場合、同じデータを複数回削除しても同様の効果が得られます。ただし、クエリ条件による削除は必ずしも冪等性を満たすわけではないことに注意してください。例えば、条件に従ってデータを一括削除した後、条件を満たすデータを新たに追加し、再度削除を行うと、新たに追加された条件を満たすデータも削除されます。

6.べき等性を達成する方法

データベースの一意の主キー

ソリューションの説明

データベース内の一意の主キーの実装では、主にデータベース内の主キーの一意の制約特性が利用されます。一般的に言えば、一意の主キーは、「挿入」中の冪等性に適しており、レコードが 1 つだけであることを保証できます。一意の主キーを持つものはテーブル内に存在できます。データベースの一意の主キーを使用して冪等性を実現する場合、グローバルな一意性を確保するために、主キーは通常、データベース内で自動インクリメントされる主キーを使用せず、分散 ID を主キーとして使用することに注意してください。分散環境における ID の性別

適用可能な操作:

  • 挿入操作
  • 削除操作

使用制限:

  • グローバルに一意の主キー ID を生成する必要があります。

主なプロセス:

主なプロセス:

  • クライアントは作成リクエストを実行し、サーバー インターフェイスを呼び出します。
  • サーバーはビジネス ロジックを実行し、分散 ID を生成し、その ID を挿入するデータの主キーとして使用してから、データ挿入操作を実行して、対応する SQL ステートメントを実行します。
  • サーバーはデータをデータベースに挿入します。挿入が成功した場合は、インターフェイスが繰り返し呼び出されないことを意味します。主キー重複例外がスローされた場合は、レコードがデータベースにすでに存在していることを意味し、クライアントにエラー メッセージが返されます。

データベースの楽観的ロック

プログラムの説明:

データベースのオプティミスティック ロック スキームは、通常、「更新操作」を実行するプロセスにのみ適用されます。現在のデータのバージョン識別子として機能するフィールドを、対応するデータ テーブルに事前に追加できます。このように、データベースのこのテーブルのこのデータが更新されるたびに、バージョン識別子が条件として使用され、値は最後に更新されるデータのバージョン識別子の値になります。

適用可能な操作:

  • 更新操作

使用制限:

  • 追加のフィールドをデータベース内の対応するビジネス テーブルに追加する必要があります。

記述例:

たとえば、次のデータテーブルが存在します。

ピド 名前 価格
1 シャオミの携帯電話 1000
2 iPhone 2500
3 ファーウェイの携帯電話 1600

更新が実行されるたびに更新が繰り返されることを防ぎ、更新されたコンテンツが必ず更新されるコンテンツであることを保証するために、通常、現在のレコードのバージョンを記録するバージョン フィールドを追加して、更新時に値がもたらされるようにします。更新操作が実行される限り、更新が必要な情報が該当するバージョンの情報であることを確認してください。

ピド 名前 価格 バージョン
1 シャオミの携帯電話 1000 10
2 iPhone 2500 21
3 ファーウェイの携帯電話 1600 5

このように、アップデートを実行するたびに、アップデートするバージョン番号を指定する必要がありますが、次の操作により、正確に version=5 の情報を更新できます。

UPDATE my_table SET price = price + 50, version = version + 1 WHERE pid = 1 AND version = 5

上記の WHERE の後に、pid = 1 AND version = 5 という条件が続きます。実行後、pid = 1 のバージョンは 6 に更新されるため、繰り返し SQL 文を実行すると、pid のデータが失われるため、SQL ステートメントは有効になりません。 = 1 AND version = 5 は有効ではなくなりました。これにより、更新の冪等性が維持され、複数の更新が結果に影響を与えることはありません。

重複防止トークン トークン

プログラムの説明:

クライアントによる連続クリックや、注文送信などの呼び出し元によるタイムアウト再試行などの状況では、トークン メカニズムを使用して、繰り返し送信を防ぐことができます。簡単に言うと、呼び出し元はインターフェイスを呼び出すときに、最初にバックエンドにグローバル ID (トークン) を要求します。要求する際には、このグローバル ID も一緒に送信します (トークンをヘッダーに置くのが最善です)。バックエンドは次を使用する必要があります。このTokenをKeyとして、ユーザー情報をValueとしてRedisに送信し、Key値の内容検証を行い、Keyが存在し、Valueが一致する場合には削除コマンドが実行され、以降のビジネスロジックが正常に実行されます。対応するキーがない場合、または値が一致しない場合は、冪等な操作を保証するためにエラー メッセージが繰り返し返されます。

適用可能な操作:

  • 挿入操作;
  • 更新操作。
  • 削除操作。

使用制限:

  • グローバルに一意のトークン文字列を生成する必要があります。
  • データ検証にはサードパーティ コンポーネント Redis を使用する必要があります。

主なプロセス:

  • サーバーはトークンを取得するためのインターフェイスを提供します。トークンはシリアル番号、配布 ID、または UUID 文字列です。

  • クライアントはインターフェイスを呼び出してトークンを取得しますが、このときサーバーはトークン文字列を生成します。

  • 次に、トークンを Redis キーとして使用して、文字列を Redis データベースに保存します (有効期限が設定されていることに注意してください)。

  • トークンをクライアントに返します。クライアントがトークンを取得したら、フォームの非表示フィールドに保存する必要があります。

  • クライアントがフォームを実行して送信すると、トークンがヘッダーに保存され、ビジネス リクエストの実行時にヘッダーが一緒に送信されます。

  • リクエストを受信した後、サーバーはヘッダーからトークンを取得し、そのトークンに基づいてキーが Redis に存在するかどうかを確認します。

  • サーバーは、Redis にキーが存在するかどうかを判断し、存在する場合はキーを削除し、ビジネス ロジックを通常どおり実行します。存在しない場合は、例外がスローされ、繰り返し送信されるとエラー メッセージが返されます。

同時実行条件では、Redis データの検索と削除を実行するときにアトミック性を保証する必要があることに注意してください。そうしないと、同時実行下で冪等性が保証されない可能性があります。この実装方法では、分散ロックを使用するか、Lua 式を使用してクエリをログアウトし、操作を削除できます。

一意のシーケンス番号を下流に渡します

プログラムの説明:

いわゆるリクエスト シーケンス番号は、実際には、サーバーへの各リクエストに、短期間に一意で反復しないシーケンス番号が付随することを意味します。シーケンス番号は、連続した ID または順序番号になります。一般に生成されます。呼び出し時 上流サーバーインターフェースはシリアル番号と認証に使用する ID を付加します。上流サーバーはリクエスト情報を受信すると、シリアル番号と下流認証 ID を組み合わせて Redis を操作するための Key を形成し、対応する Key に対応するキーと値のペアがあるかどうかを Redis に問い合わせます。 :

  • 存在する場合は、そのシーケンス番号に対するダウンストリーム リクエストが処理されたことを意味します。この時点では、繰り返されたリクエストのエラー メッセージに直接応答できます。
  • 存在しない場合は、キーを Redis のキーとして使用し、ダウンストリームのキー情報を保存された値 (ダウンストリーム プロバイダーによって渡されたビジネス ロジック情報など) として使用し、キーと値のペアを Redis に保存してから実行します。対応するビジネスは通常通りです。

適用可能な操作:

  • 挿入操作;
  • 更新操作。
  • 削除操作。

使用制限:

  • 第三者に一意のシリアル番号を渡すよう要求する。
  • データ検証にはサードパーティ コンポーネント Redis を使用する必要があります。

主なプロセス:

主な手順:

  • ダウンストリーム サービスは、配布 ID をシリアル番号として生成し、「固有のシリアル番号」と要求された「認証資格情報 ID」とともに、アップストリーム インターフェイスを呼び出すリクエストを実行します。
  • アップストリーム サービスはセキュリティ検証を実行し、ダウンストリームに渡されたパラメータに「シリアル番号」と「資格情報 ID」があるかどうかを検出します。
  • 上流サービスは、Redis にアクセスして、対応する「シリアル番号」と「認証 ID」で構成される Key が存在するかどうかを検出し、存在する場合は、繰り返し実行例外メッセージをスローし、サービスからの対応するエラー メッセージに応答します。下流。存在しない場合は、「シリアル番号」と「認証ID」の組み合わせをキーとし、下流のキー情報を値としてRedisに格納し、以降のビジネスロジックを通常通り実行します。

上記の手順では、Redis にデータを挿入するときに、有効期限を設定する必要があります。これにより、この時間範囲内でインターフェイスが繰り返し呼び出された場合でも、判断と識別を行うことができます。有効期限が設定されていない場合、無制限の量のデータが Redis に保存され、Redis が適切に動作しなくなる可能性があります。

7. 冪等インタフェースの例

ここでは重複防止トークン スキームが使用されており、さまざまなリクエスト アクションで冪等性を確保できます。実装ロジックについては、上記の「重複防止トークン」スキームを参照してください。次に、このロジックを実装するコードを作成します。

Maven に関連する依存関係が導入される

ここでは依存関係を管理するために Maven ツールが使用されており、SpringBoot、Redis、および lombok 関連の依存関係が pom.xml に導入されています。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.4.RELEASE</version>
    </parent>

    <groupId>mydlq.club</groupId>
    <artifactId>springboot-idempotent-token</artifactId>
    <version>0.0.1</version>
    <name>springboot-idempotent-token</name>
    <description>Idempotent Demo</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--springboot web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--springboot data redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Redis に接続するためのパラメーターを構成する

アプリケーション構成ファイルで Redis に接続するためのパラメーターを構成します。Spring Boot の基本については紹介しませんが、最新のチュートリアルについては、以下のチュートリアルを読むことをお勧めします。

次のように:

spring:
  redis:
    ssl: false
    host: 127.0.0.1
    port: 6379
    database: 0
    timeout: 1000
    password:
    lettuce:
      pool:
        max-active: 100
        max-wait: -1
        min-idle: 0
        max-idle: 20

トークンツールクラスの作成と検証

トークンを操作するためのサービス クラスを作成します。これには、トークンの作成メソッドと検証メソッドが含まれます。その中には次のものが含まれます。

  • トークンの作成方法: UUID ツールを使用してトークン文字列を作成し、「idempotent_token:」+「トークン文字列」をキーとして設定し、ユーザー情報を値として使用し、情報を Redis に保存します。
  • トークン検証方法:トークン文字列パラメーターを受け取り、キー プレフィックスを追加してキーを形成し、値を渡して、Lua 式 (Lua 式はコマンド実行のアトミック性を保証できます) を実行して、対応するキーを見つけて操作を削除します。 。実行が完了したら、コマンドの戻り結果を検証します。結果が空でなく、0 以外であれば検証は成功し、それ以外の場合は失敗します。
import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class TokenUtilService {
    
    

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 存入 Redis 的 Token 键的前缀
     */
    private static final String IDEMPOTENT_TOKEN_PREFIX = "idempotent_token:";

    /**
     * 创建 Token 存入 Redis,并返回该 Token
     *
     * @param value 用于辅助验证的 value 值
     * @return 生成的 Token 串
     */
    public String generateToken(String value) {
    
    
        // 实例化生成 ID 工具对象
        String token = UUID.randomUUID().toString();
        // 设置存入 Redis 的 Key
        String key = IDEMPOTENT_TOKEN_PREFIX + token;
        // 存储 Token 到 Redis,且设置过期时间为5分钟
        redisTemplate.opsForValue().set(key, value, 5, TimeUnit.MINUTES);
        // 返回 Token
        return token;
    }

    /**
     * 验证 Token 正确性
     *
     * @param token token 字符串
     * @param value value 存储在Redis中的辅助验证信息
     * @return 验证结果
     */
    public boolean validToken(String token, String value) {
    
    
        // 设置 Lua 脚本,其中 KEYS[1] 是 key,KEYS[2] 是 value
        String script = "if redis.call('get', KEYS[1]) == KEYS[2] then return redis.call('del', KEYS[1]) else return 0 end";
        RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
        // 根据 Key 前缀拼接 Key
        String key = IDEMPOTENT_TOKEN_PREFIX + token;
        // 执行 Lua 脚本
        Long result = redisTemplate.execute(redisScript, Arrays.asList(key, value));
        // 根据返回结果判断是否成功成功匹配并删除 Redis 键值对,若果结果不为空和0,则验证通过
        if (result != null && result != 0L) {
    
    
            log.info("验证 token={},key={},value={} 成功", token, key, value);
            return true;
        }
        log.info("验证 token={},key={},value={} 失败", token, key, value);
        return false;
    }

}

テストコントローラークラスを作成する

Tokenの取得とその冪等性をテストするインターフェースを持ったテスト用のControllerクラスを作成します。

import lombok.extern.slf4j.Slf4j;
import mydlq.club.example.service.TokenUtilService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
public class TokenController {
    
    

    @Autowired
    private TokenUtilService tokenService;

    /**
     * 获取 Token 接口
     *
     * @return Token 串
     */
    @GetMapping("/token")
    public String getToken() {
    
    
        // 获取用户信息(这里使用模拟数据)
        // 注:这里存储该内容只是举例,其作用为辅助验证,使其验证逻辑更安全,如这里存储用户信息,其目的为:
        // - 1)、使用"token"验证 Redis 中是否存在对应的 Key
        // - 2)、使用"用户信息"验证 Redis 的 Value 是否匹配。
        String userInfo = "mydlq";
        // 获取 Token 字符串,并返回
        return tokenService.generateToken(userInfo);
    }

    /**
     * 接口幂等性测试接口
     *
     * @param token 幂等 Token 串
     * @return 执行结果
     */
    @PostMapping("/test")
    public String test(@RequestHeader(value = "token") String token) {
    
    
        // 获取用户信息(这里使用模拟数据)
        String userInfo = "mydlq";
        // 根据 Token 和与用户相关的信息到 Redis 验证是否存在对应的信息
        boolean result = tokenService.validToken(token, userInfo);
        // 根据验证结果响应不同信息
        return result ? "正常调用" : "重复调用";
    }

}

SpringBootスタートアップクラスを作成する

SpringBoot アプリケーションを起動するためのスタートアップ クラスを作成します。基本的なチュートリアルは紹介しませんが、非常に充実した次のチュートリアルを読むことをお勧めします。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    
    

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

}

テスト用のテストクラスを作成する

テストするテストクラスを作成し、同じインターフェースに複数回アクセスして、初回のみ正常に実行できるかどうかをテストします。

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class IdempotenceTest {
    
    

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Test
    public void interfaceIdempotenceTest() throws Exception {
    
    
        // 初始化 MockMvc
        MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
        // 调用获取 Token 接口
        String token = mockMvc.perform(MockMvcRequestBuilders.get("/token")
                .accept(MediaType.TEXT_HTML))
                .andReturn()
                .getResponse().getContentAsString();
        log.info("获取的 Token 串:{}", token);
        // 循环调用 5 次进行测试
        for (int i = 1; i <= 5; i++) {
    
    
            log.info("第{}次调用测试接口", i);
            // 调用验证接口并打印结果
            String result = mockMvc.perform(MockMvcRequestBuilders.post("/test")
                    .header("token", token)
                    .accept(MediaType.TEXT_HTML))
                    .andReturn().getResponse().getContentAsString();
            log.info(result);
            // 结果断言
            if (i == 0) {
    
    
                Assert.assertEquals(result, "正常调用");
            } else {
    
    
                Assert.assertEquals(result, "重复调用");
            }
        }
    }

}

次のように表示されます。

[main] IdempotenceTest:  获取的 Token 串:980ea707-ce2e-456e-a059-0a03332110b4
[main] IdempotenceTest:  第1次调用测试接口
[main] IdempotenceTest:  正常调用
[main] IdempotenceTest:  第2次调用测试接口
[main] IdempotenceTest:  重复调用
[main] IdempotenceTest:  第3次调用测试接口
[main] IdempotenceTest:  重复调用
[main] IdempotenceTest:  第4次调用测试接口
[main] IdempotenceTest:  重复调用
[main] IdempotenceTest:  第5次调用测试接口
[main] IdempotenceTest:  重复调用

8. まとめ

冪等性は開発において非常に一般的かつ重要な要件であり、特に支払いや注文などの金銭に関連するサービスの場合、インターフェイスの冪等性を確保することが特に重要です。実際の開発では、さまざまなビジネス シナリオに合わせて冪等な実装方法を柔軟に選択する必要があります。

  • 一意の主キーを持つ注文の場合は、「一意の主キー ソリューション」を使用できます。
  • 注文ステータスの更新など、関連する更新シナリオ操作については、「オプティミスティック ロック スキーム」を使用する方が実装が簡単です。
  • アップストリームとダウンストリームの状況で、ダウンストリームがアップストリームを要求する場合、アップストリーム サービスはより合理的な「ダウンストリーム配信固有のシーケンス番号スキーム」を使用できます。
  • フロントエンドが繰り返し送信、繰り返し注文し、固有の ID 番号を持たないシナリオと同様に、Token と Redis と連携する「重複防止トークン ソリューション」により、より迅速に実装できます。

上記はほんの一部の提案です。冪等性を実現するには、まず自社のビジネス ニーズを理解し、ビジネス ロジックに従って実装する必要があります。各ノードの詳細を適切に処理し、ビジネス プロセス全体を改善することによってのみ実現できることをもう一度強調したいと思います。システムが正常に動作することを保証するのに適しています。

スキーム名 適用可能な方法 実装の複雑さ ソリューションの欠点
データベースの一意の主キー 挿入操作 削除操作 単純 - 挿入操作にのみ使用できます。 - 一意の主キーが存在するシナリオでのみ使用できます。
データベースの楽観的ロック 更新操作 単純 - 更新操作にのみ使用できます。 - 追加のフィールドをテーブルに追加する必要があります。
シリアル番号を要求する 挿入操作 更新操作 削除操作 単純 - ダウンストリームが一意のシリアル番号を生成することを確認する必要がある; - 要求されたシリアル番号を保存するにはサードパーティとして Redis が必要である。
重複防止トークン トークン 挿入操作 更新操作 削除操作 適度 - Redis サードパーティ ストレージによって生成されたトークン文字列が必要です。

おすすめ

転載: blog.csdn.net/weixin_43874301/article/details/131527531