最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java+MySQL實現(xiàn)設(shè)計優(yōu)惠券系統(tǒng)

 更新時間:2022年05月22日 09:14:11   作者:??Java架構(gòu)師????  
這篇文章主要介紹了Java+MySQL實現(xiàn)設(shè)計優(yōu)惠券系統(tǒng),文章基于Java與MySQL的相關(guān)資料展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下

1 Scenario 場景

電商系統(tǒng)的促銷手段(Electronic Commerce Systems):

  • 優(yōu)惠券
  • 拼團
  • 砍價
  • 老帶新

優(yōu)惠券的種類:

  • 滿減券
  • 直減券
  • 折扣券

優(yōu)惠券系統(tǒng)的核心流程:

發(fā)券

發(fā)券的方式: 同步發(fā)送 or 異步發(fā)送

領(lǐng)券

  • 誰能領(lǐng)?
  • 所有用戶 or 指定的用戶
  • 領(lǐng)取上限
  • 一個優(yōu)惠券最多能領(lǐng)取多少張?
  • 領(lǐng)取方式
  • 用戶主動領(lǐng)取 or 自動發(fā)放被動領(lǐng)取

用券

  • 作用范圍
  • 商品、商戶、類目
  • 計算方式
  • 是否互斥、是否達到門檻等

需求拆解

商家側(cè):

  • 創(chuàng)建優(yōu)惠券
  • 發(fā)送優(yōu)惠券

用戶側(cè):

  • 領(lǐng)取優(yōu)惠券
  • 下單
  • 使用優(yōu)惠券
  • 支付

2 Service 服務(wù)

2.1 服務(wù)結(jié)構(gòu)設(shè)計

2.2 優(yōu)惠券系統(tǒng)難點

券的分布式事務(wù),使用券的過程會出現(xiàn)的分布式問題分析

如何防止超發(fā)

如何大批量給用戶發(fā)券

如何限制券的使用條件

如何防止用戶重復(fù)領(lǐng)券

3 Storage存儲

模型的設(shè)計

優(yōu)惠券系統(tǒng) Coupon System 模型定義

優(yōu)惠券系統(tǒng)的難點

3.1 表單設(shè)計

券批次(券模板),coupon_batch

指一批優(yōu)惠券的抽象、模板,包含優(yōu)惠券的大部分屬性。

如商家創(chuàng)建了一批優(yōu)惠券,共1000張,使用時間為2022-11-11 00:00:00 ~ 2022-11-11 23:59:59,規(guī)定只有數(shù)碼類目商品才能使用,滿100減50。

發(fā)放到用戶的一個實體,已與用戶綁定。

如將某批次的優(yōu)惠券中的一張發(fā)送給某個用戶,此時優(yōu)惠券屬于用戶。

規(guī)則

優(yōu)惠券的使用有規(guī)則和條件限制,比如滿100減50券,需要達到門檻金額100元才能使用。

券批次表 coupon_batch

規(guī)則表 rule:

規(guī)則內(nèi)容:

 {
   threshold: 5.01 // 使用門檻
   amount: 5 // 優(yōu)惠金額
   use_range: 3 // 使用范圍,0—全場,1—商家,2—類別,3—商品 
   commodity_id: 10 // 商品 id
   receive_count: 1 // 每個用戶可以領(lǐng)取的數(shù)量
   is_mutex: true // 是否互斥,true 表示互斥,false 表示不互斥
   receive_started_at: 2020-11-1 00:08:00 // 領(lǐng)取開始時間
   receive_ended_at: 2020-11-6 00:08:00 // 領(lǐng)取結(jié)束時間
   use_started_at: 2020-11-1 00:00:00 // 使用開始時間
   use_ended_at: 2020-11-11 11:59:59 // 使用結(jié)束時間
 }

優(yōu)惠券表 coupon:

 create table t_coupon
 (
     coupon_id     int          null comment '券ID,主鍵',
     user_id       int          null comment '用戶ID',
     batch_id      int          null comment '批次ID',
     status        int          null comment '0-未使用、1-已使用、2-已過期、3-凍結(jié)',
     order_id      varchar(255) null comment '對應(yīng)訂單ID',
     received_time datetime     null comment '領(lǐng)取時間',
     validat_time  datetime     null comment '有效日期',
     used_time     datetime     null comment '使用時間'
 );

3.2 優(yōu)惠券系統(tǒng)

建券:

1、新建規(guī)則

 INSERT INTO rule (name, type, rule_content)
 VALUES(“滿減規(guī)則”, 0, '{
                         threshold: 100
                         amount: 10
                         ......
                       }');

2、新建優(yōu)惠券批次

 INSERT INTO coupon_batch (coupon_name, rule_id, total_count ) 
 VALUES(“勞斯萊斯5元代金券”, 1010, 10000);

發(fā)券:

如何給大量用戶發(fā)券?

異步發(fā)送

觸達系統(tǒng)

  • 短信、郵件
  • 可通過調(diào)用第三方接口的方式實現(xiàn)
  • 站內(nèi)信
  • 通過數(shù)據(jù)庫插入記錄來實現(xiàn)

信息表 message

 create table t_message
 (
     id         int null comment '信息ID',
     send_id    int null comment '發(fā)送者id',
     rec_id     int null comment '接受者id',
     content    vachar(255) comment '站內(nèi)信內(nèi)容',
     is_read    int null comment '是否已讀',
     send_time  datetime comment '發(fā)送時間'
 )
 comment '信息表';

先考慮用戶量很少的情況,商家要給所有人發(fā)站內(nèi)信,則先遍歷用戶表,再按照用戶表中的所有用戶依次將站內(nèi)信插入到 message 表中。這樣,如果有100個用戶,則群發(fā)一條站內(nèi)信要執(zhí)行100個插入操作。

系統(tǒng)用戶數(shù)增加到萬級

發(fā)一條站內(nèi)信,就得重復(fù)插入上萬條數(shù)據(jù)。而且這上萬條數(shù)據(jù)的 content 一樣!假設(shè)一條站內(nèi)信占100K,發(fā)一次站內(nèi)信就要消耗十幾M。對此,可將原來的表拆成兩個表:

信息表 message

信息內(nèi)容表 message_content

發(fā)一封站內(nèi)信的步驟

  • 往 message_content 插入站內(nèi)信的內(nèi)容
  • 在 message 表中,給所有用戶插入一條記錄,標識有一封站內(nèi)信

千w級用戶數(shù)

這就有【非活躍用戶】的問題,假設(shè)注冊用戶一千萬,根據(jù)二八原則,其中活躍用戶占20%。若采用上面拆成兩個表的情況,發(fā)一封“站內(nèi)信”,得執(zhí)行一千萬個插入操作??赡苁O?0%用戶基本都不會再登錄,其實只需對其中20%用戶插入數(shù)據(jù)。

信息表 message:

 create table t_message
 (
     id         int null comment '信息 ID',
     # send_id    int null comment '發(fā)送者 id', 去除該字段
     rec_id     int null comment '接受者 id',
     message_id int null comment '外鍵,信息內(nèi)容',
     is_read    int null comment '是否已讀'
 )
     comment '信息表';
 create table t_message_content
 (
     id        int          null comment '信息內(nèi)容id',
     send_id    int         null comment '發(fā)送者id',
     content   varchar(255) null comment '內(nèi)容',
     send_time datetime     null comment '發(fā)送時間'
 );

用戶側(cè)操作

登錄后,首先查詢 message_content 中的那些沒有在 message 中有記錄的數(shù)據(jù),表示是未讀的站內(nèi)信。在查閱站內(nèi)信的內(nèi)容時,再將相關(guān)的記錄插入 message。

系統(tǒng)側(cè)操作

發(fā)站內(nèi)信時:

  • 只在 message_content 插入站內(nèi)信的主體內(nèi)容
  • message 不插入記錄

假設(shè)商家要給 10W 用戶發(fā)券:

有什么問題?重復(fù)消費,導(dǎo)致超發(fā)!

  • 運營提供滿足條件的用戶文件,上傳到發(fā)券管理后臺并選擇要發(fā)送的優(yōu)惠券
  • 管理服務(wù)器根據(jù)【用戶ID】、【券批次ID】生成消息,發(fā)送到MQ
  • 優(yōu)惠券服務(wù)器消費消息
 # 記住使用事務(wù)哦!
 INSERT INTO coupon (user_id, coupon_id,batch_id)
   VALUES(1001, 66889, 1111);
 
 UPDATE coupon_batch SET total_count = total_count - 1,
                           assign_count = assign_count + 1
                       WHERE batch_id = 1111 AND total_count > 0; 

領(lǐng)券

步驟:

  • 校驗優(yōu)惠券余量
 SELECT total_count FROM coupon_batch 
   WHERE batch_id = 1111; 
  • 新增優(yōu)惠券用戶表,扣減余量
 # 注意事務(wù)!
 INSERT INTO coupon (user_id, coupon_id,batch_id)
   VALUES(1001, 66889, 1111); 
 
 UPDATE coupon_batch SET total_count = total_count - 1,
                           assign_count = assign_count + 1
                       WHERE batch_id = 1111 AND total_count > 0;

用戶領(lǐng)券過程中,其實也會出現(xiàn)類似秒殺場景。秒殺場景下會有哪些問題,如何解決?

解決用戶重復(fù)領(lǐng)取或多領(lǐng):

Redis 數(shù)據(jù)校驗!

  • 領(lǐng)券前,先查緩存
 # 判斷成員元素是否是集合的成員
 SISMEMBER KEY VALUE
 SISMEMBER batch_id:1111:user_id 1001
  • 領(lǐng)券
  • 領(lǐng)券后,更新緩存
 # 將一或多個成員元素加入到集合中,已經(jīng)存在于集合的成員元素將被忽略 
 SADD KEY VALUE1......VALUEN
 SADD batch_id:1111:user_id 1001

用券

何時校驗優(yōu)惠券使用規(guī)則?

  • 確認訂單(√)
  • 提交訂單
  • 立即付款

確認訂單頁,對優(yōu)惠券進行校驗:

  • 判斷是否過期
  • 判斷適用范圍
  • 判斷是否達到門檻
  • 判斷是否互斥

返回可用券

 SELECT batch_id FROM coupon WHERE user_id = 1001 AND status = 0;
 
 SELECT rule_id FROM coupon_batch WHERE batch_id = 1111;
 
 SELECT name, type, rule_content FROM rule WHERE rule_id = 1010;
復(fù)制代碼

選擇可用券,并返回結(jié)果

同時操作多個服務(wù),如何保證一致性?

表設(shè)計

優(yōu)惠券操作記錄表 Coupon_opt_record

 create table t_coupon_opt_record
 (
     user_id     int      null comment '用戶id',
     coupon_id   int      null comment '優(yōu)惠券id',
     operating   int      null comment '操作,0-鎖定、1-核銷、2-解鎖',
     operated_at datetime null comment '操作時間'
 );

TCC,Try-Confirm-Cancel,目前分布式事務(wù)主流解決方案。

階段一:Try

對資源進行凍結(jié),預(yù)留業(yè)務(wù)資源

創(chuàng)建訂單時,將優(yōu)惠券狀態(tài)改為 “凍結(jié)”

階段二:Confirm

確認執(zhí)行業(yè)務(wù)操作,做真正提交,將第一步Try中凍結(jié)的資源,真正扣減

訂單支付成功,將優(yōu)惠券狀態(tài)改為 “已使用”

階段三:Cancel

取消執(zhí)行業(yè)務(wù)操作,取消Try階段預(yù)留的業(yè)務(wù)資源

支付失敗/超時或訂單關(guān)閉情況,將優(yōu)惠券狀態(tài)改為 “未使用”

Scale擴展

快過期券提醒:

定時掃券表:

缺點:掃描數(shù)據(jù)量太大,隨著歷史數(shù)據(jù)越來越多,會影響線上主業(yè)務(wù),最終導(dǎo)致慢SQL。

延時消息:

缺點:有些券的有效時間太長了(30天)以上,有可能造成大量 MQ 積壓

新增通知表:

優(yōu)點:掃描的數(shù)據(jù)量小,效率高。刪除無用的已通知的數(shù)據(jù)記錄

通知信息表(notify_msg)設(shè)計

 create table t_notify_msg
 (
     id          bigint auto_increment comment '自增主鍵',
     coupon_id   bigint       null comment '券id',
     user_id     bigint       null comment '用戶id',
     notify_day  varchar(255) null comment '需要執(zhí)行通知的日期',
     notify_type int          null comment '通知類型,1-過期提醒',
     notif_time  timestamp    null comment '通知的時間,在該時間戳所在天內(nèi)通知',
     status      int          null comment '通知狀態(tài),0-初始狀態(tài)、1-成功、2-失敗',
     constraint t_notify_msg_id_uindex
         unique (id)
 );
 alter table t_notify_msg
     add primary key (id);

過期券提醒:

  • 在創(chuàng)建優(yōu)惠券的時候就將需要提醒的記錄插入提醒表中notify_msg
  • 把用戶ID+批次ID+通知日期作為唯一索引,防止同一個批次有重復(fù)的記錄通知,保證每天只會被通知一次
  • 建立notify_time,通知時間索引,每日的通知掃描通過該索引列查詢,通過索引列來提高查詢效率
  • 通知完成后該表中的數(shù)據(jù)變失去了意義,通過定時任務(wù)將該數(shù)據(jù)刪除

數(shù)據(jù)庫層面優(yōu)化 - 索引

發(fā)券接口,限流保護

前端限流:

點擊一次后,按鈕短時間內(nèi)置灰

后端限流:

部分請求直接跳轉(zhuǎn)到【繁忙頁】

到此這篇關(guān)于Java+MySQL實現(xiàn)設(shè)計優(yōu)惠券系統(tǒng)的文章就介紹到這了,更多相關(guān)Java+MySQ設(shè)計系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java反射技術(shù)原理與用法實例分析

    Java反射技術(shù)原理與用法實例分析

    這篇文章主要介紹了Java反射技術(shù)原理與用法,結(jié)合實例形式分析了Java反射技術(shù)的基本概念、功能、原理、用法及操作注意事項,需要的朋友可以參考下
    2020-04-04
  • MyBatis通用Mapper和PageHelper的過程詳解

    MyBatis通用Mapper和PageHelper的過程詳解

    這篇文章主要介紹了MyBatis通用Mapper和PageHelper的相關(guān)知識,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Java字節(jié)緩存流的構(gòu)造方法之文件IO流

    Java字節(jié)緩存流的構(gòu)造方法之文件IO流

    這篇文章主要介紹了Java字節(jié)緩存流的構(gòu)造方法之文件IO流,同時也介紹了字符流中的一些相關(guān)的內(nèi)容,并且通過大量的案例供大家理解。最后通過一些經(jīng)典的案例幫助大家對前面所學的知識做了一個綜合的應(yīng)用,需要的朋友可以參考一下
    2022-04-04
  • Java中List.of()和Arrays.asList()的區(qū)別及原因分析

    Java中List.of()和Arrays.asList()的區(qū)別及原因分析

    這篇文章主要介紹了Java中List.of()和Arrays.asList()的區(qū)別及原因分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • spring boot基于DRUID實現(xiàn)數(shù)據(jù)源監(jiān)控過程解析

    spring boot基于DRUID實現(xiàn)數(shù)據(jù)源監(jiān)控過程解析

    這篇文章主要介紹了spring boot基于DRUID實現(xiàn)數(shù)據(jù)源監(jiān)控過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • java使用Jsoup連接網(wǎng)站超時的解決方法

    java使用Jsoup連接網(wǎng)站超時的解決方法

    jsoup是一個非常好的解析網(wǎng)頁的包,用java開發(fā)的,提供了類似DOM,CSS選擇器的方式來查找和提取文檔中的內(nèi)容,提取文檔內(nèi)容時會出現(xiàn)超時的情況,解決方法可看下文
    2013-11-11
  • MyBatis Mapper代理使用方法詳解

    MyBatis Mapper代理使用方法詳解

    本文是小編日常收集整理的關(guān)于mybatis mapper代理使用方法知識,通過本文還給大家提供有關(guān)開發(fā)規(guī)范方面的知識點,本文介紹的非常詳細,具有參考借鑒價值,感興趣的朋友一起看下吧
    2016-08-08
  • 清理本地Maven倉庫的方法示例

    清理本地Maven倉庫的方法示例

    這篇文章主要介紹了清理本地Maven倉庫的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • Springboot 如何使用@Async整合線程池

    Springboot 如何使用@Async整合線程池

    這篇文章主要介紹了Springboot 使用@Async整合線程池的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 使用java為pdf添加書簽的方法(pdf書簽制作)

    使用java為pdf添加書簽的方法(pdf書簽制作)

    下載一些pdf格式的電子書沒有書簽,用JAVA寫了一個小工具,將特定格式的文本解析成為書簽,然后保存到pdf格式中
    2014-02-02

最新評論

金门县| 犍为县| 花莲市| 河曲县| 垣曲县| 泾川县| 泾阳县| 页游| 离岛区| 奉新县| 潜山县| 礼泉县| 东城区| 同江市| 常州市| 博湖县| 灵山县| 常熟市| 庄浪县| 拉萨市| 广汉市| 周宁县| 永修县| 宝鸡市| 新化县| 临猗县| 连山| 成都市| 洪泽县| 儋州市| 兴和县| 丘北县| 南京市| 凤冈县| 通辽市| 胶州市| 灵石县| 瓦房店市| 昭平县| 安西县| 垣曲县|