アプリケーション開発プラットフォーム ビジネスサポート機能 - ドキュメント番号、シリアル番号機能スキーム、設計および実装

バックグラウンド

通常、業務システムには業務上の意味を持ったシリアル番号を生成する機能があり、シリアル番号は一意である必要があり、通常は業務上の意味を持つ文字列(任意)+年月日(年または月日)の3つの部分から構成されます。年、月、または年、月、日、時刻などは任意)+ 一連の番号(1 から始まる)(HT201910080003 など)。これは、2019 年 10 月 8 日に作成された 3 番目の契約を意味します。
シリアル番号の設定は、IT 管理者によって維持および管理されます。

プラン選択

シリアル番号と通常のエンティティの間には、まだいくつかの違いがあります。ある程度、エンティティに従属するものです。シリアル番号を管理する方法には、次の 2 つの主な解決策があります。 解決策 1: 独立した管理、シリアル番号を構成
するルールを設定し、エンティティ モデルの構成時にシリアル番号エンティティを選択する レコードが関連付けられる
スキーム 2: エンティティの構成時に構成が実行され、エンティティ モデルに従属する
これら 2 つのスキームには、それぞれ長所と短所があります。解決策 1 では、エンティティを構成する前にエンティティに対応するシリアル番号ルールを作成する必要があり、その手順が少し面倒です。オプション 2 は通常の順序で実行されますが、エンティティ モデルに完全に従属し、独立した表示ページはなくなります。

ビジネス機能の観点から見ると、シリアル番号の設定にはプレフィックス、期間、シリアル番号を設定する必要があります。エンティティ モデルを設定するプロセスでのシリアル番号の設定は少し重いです。設定する方が合理的です。エンティティ モデルの設定を直接使用することもできます。
また、シリアル番号の記録には、生成規則だけでなく、現在のシリアル番号も記録されており、リセット規則に従ってリセットされますので、システム異常時のトラブルシューティング時には、独立した閲覧ページで確認してください。エンティティ設定で現在のルールとシリアル番号の値を確認しますが、動作がおかしいようです。
特に重要なのは、シリアル番号ルールはビジネスの変更に応じて調整されることですが、変更の頻度はエンティティ独自の構成よりもはるかに高いため、個別に保守する方がよいということです。
また、複数の文書で通し番号を共有するビジネスシナリオも考えられますが、この場合、スキーム2のサブ事業体モードを使用すると要件を満たせず、機能を実現できません。

要約すると、オプション 1 を使用しても、これは依然として独立して管理され、エンティティ構成の前に事前構成されるだけなので、問題はありません。この場合、シリアル番号は通常のものとなり、一覧表示、追加、削除、変更、問い合わせのメニューが独立したものとなります。

機能の設計と実装

基本機能

新規: ドキュメントのシリアル番号データ レコードを作成し、シリアル番号の生成ルールとリセット戦略を構成します。
編集: 将来生成する必要があるシリアル番号に対してのみドキュメントのシリアル番号を調整し、過去のドキュメントのシリアル番号を遡及的に調整しません。削除
: Tombstone
クエリ: 文書タイプと文書名に基づいたシリアル番号生成ルールをクエリ


画像.png
エンティティ構成モジュールの動作効果に基づく
画像.png

シリアル番号生成ルール

最大 3 つの段落 (プレフィックス (オプション) + 日付と時刻の書式文字列 (オプション) + いくつかのシリアル番号) を選択して文字列を接続できます。デフォルトは空の文字列です。 プレフィックス: ビジネス上の意味を持つ文字列 (通常は英語
)ビジネス文書の単語または中国語のピンインの頭字語
日付と時刻の形式文字列: yyyyMMddHHmmssの形式に準拠した文字列または先頭の同じ部分に準拠した文字列(たとえば、yyyyMMddのみを入力)を柔軟に入力できます。プログラムは現在時刻に従って変換します。
シリアル番号: 1 から番号付けを開始し、桁数が足りない場合はゼロを埋め込みます。

画像.png

拡張子

単一のシリアル番号を取得する: バックエンド サービス、文書タイプを渡す、単一のシリアル番号を取得する シリアル番号を
バッチで取得する: バックエンド サービス、文書タイプと数量を渡す、指定された数のシリアル番号を取得する シリアル番号を
リセットする番号: リセット戦略に従って、シリアル番号を自動的に 1 にリセットします

リセットポリシー

年別、月別、日別、タスク スケジュール機能を使用する 注
: 時間などのより細かい時間の次元は考慮しないでください。通常、ビジネスではそれほど細かくありません。

package tech.abc.platform.support.scheduler;


import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
import tech.abc.platform.common.annotation.SystemLog;
import tech.abc.platform.common.constant.CommonConstant;
import tech.abc.platform.common.enums.LogTypeEnum;
import tech.abc.platform.support.service.SerialNoService;


/**
 * 重置流水号
 *
 * @author wqliu
 * @date 2023-05-30
 */
@Component
@Slf4j
@DisallowConcurrentExecution
public class ResetSerialNo extends QuartzJobBean {
    
    

    @Autowired
    private SerialNoService serialNoService;


    @Override
    @SystemLog(value = "重置流水号", logType = LogTypeEnum.SCHEDULER, logRequestParam = false, executeResult =
            CommonConstant.NO)
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    
    

        try {
    
    
            serialNoService.resetSerialNo();
        } catch (Exception e) {
    
    
            log.error("重置流水号失败", e);
            throw new JobExecutionException(e);
        }

    }


}

画像.png

シリアル番号の一意性を保証するにはどうすればよいですか?

シリアル番号はビジネス文書の一意の番号であるため、重複しないことが保証される必要があります。そうでないと、ビジネスとシステムの通常の動作に重大な影響を及ぼします。ここでの技術的ソリューションは、主にパフォーマンスの考慮事項に基づいて、従来のロック方法を使用しません。楽観的ロック + 自動再試行メカニズムを使用してシリアル番号を生成します。オプティミスティック ロックは、MybatisPlus の緊密な統合を通じてプラットフォームによって実装され、追加の処理は必要ありません。自動再試行は、Spring の Retry 機能コンポーネントを使用します。
コンポーネントの依存関係を追加する

<!--重试组件-->
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

再試行する必要があるクラスに @Retryable アノテーションを付けます

/**
 * 批量获取流水号
 * @param code  编码
 * @param count 数量
 * @return {@link List}<{@link String}>
 */
@Override
@Retryable(value = {
    
    Exception.class}, maxAttempts = 3, backoff = @Backoff(delay = 100L, multiplier = 2))
public List<String> generateBatch(String code, int count) {
    
           
    // 先根据编码获取当前流水号
    SerialNo entity = this.lambdaQuery().eq(SerialNo::getCode, code).one();
    if (entity == null) {
    
    
        throw new CustomException(SerialNoExceptionEnum.CODE_NOT_EXIST);
    }
    int currentSerialNo = entity.getCurrentValue();
    // 计算更新后的流水号
    int updateSerialNo = currentSerialNo + count;
    // 更新数据
    entity.setCurrentValue(updateSerialNo);
    boolean updateFlag = modify(entity);
    if (!updateFlag) {
    
    
        throw new CustomException(CommonException.UPDATE_ERROR);
    }
    // 组织返回
    String template = generateNoTemplate(entity);
    List<String> result = new ArrayList<>(count);
    for (int i = 0; i < count; i++) {
    
    
        result.add(String.format(template, StringUtils.leftPad(String.valueOf(currentSerialNo), entity.getLength(),
                '0')));
        currentSerialNo++;
    }
    return result;
}

注釈パラメータとその意味は次のとおりです。

  • 値: 再試行する前に指定された例外をスローします。
  • include: value と同じで、デフォルトでは空です。exclude も空の場合、すべての例外がデフォルトになります。
  • exclude: 処理されない例外を指定します。
  • maxAttempts: 最大再試行回数、デフォルトは 3 回
  • バックオフ: 再試行待機戦略、
  • @Backoff はデフォルトで使用され、@Backoff の値はデフォルトで 1000L ですが、100 に設定します。遅延はミリ秒単位です (デフォルトは 1000)。
  • 乗数 (指定された遅延の倍数) のデフォルトは 0 で、1 秒の固定一時停止後に再試行することを意味します。乗数を 1.5 に設定すると、最初の再試行は 2 秒、2 番目の再試行は 3 秒、3 番目の再試行は 4.5 秒になります。

同じクラスに、最大再試行回数に達した後の処理のために @Recover アノテーション付きメソッドを追加する必要があります。


    /**
     * 达到最大重试次数
     *
     * @param e 异常
     */
    @Recover
    public List<String> recoverBatch(Exception e) {
    
    
        log.error("生成单据流水号达到最大重试次数", e);
        throw new CustomException(CommonException.TRY_MAX_COUNT);
    }

最後に、SpringBoot スタートアップ クラスに @EnableRetry アノテーションを忘れずに追加してください。

開発プラットフォーム情報

プラットフォーム名: One Two Three 開発プラットフォーム
紹介: エンタープライズ レベルの総合開発プラットフォーム
設計情報: csdn コラム
オープン ソース アドレス: Gitee
オープン ソース プロトコル: MIT は
お気に入り、いいね、コメントを歓迎します。あなたのサポートが私が前進する原動力です。 。

おすすめ

転載: blog.csdn.net/seawaving/article/details/131186960