# 什么是冪等性
任意多次執行所產生的影響均與一次執行的影響相同。
簡述:某個操作多次重復執行,最終結果是一致的,不會因為多次重復執行對系統造成影響。
# 什么操作會出現冪等性問題
項目里主要處理**添加接口**的冪等和**特殊情況**下的**編輯接口**冪等
1. 重復提交問題:用戶多次連續點擊提交按鈕或者網絡波動再次點擊提交
2. 重復點贊
3. Mq重復消費消息
4. 更新庫存:增減商品庫存,領取優惠券
# 常用解決方案
Token令牌,版本號,業務唯一標識
## Token令牌
主要是解決表單重復提交問題
簡單方式:每次進入表單頁面,前端去后臺獲取生成的全局唯一Token,后臺以token為key放到redis中,點擊提交時一起發給后臺,同時前端將按鈕置灰,存在則刪除 token,執行方法。
這個存在的問題是:先刪除token,還是先處理業務。
先刪除token:業務數據校驗失敗或其他異常,需要重新修改提交,則此token已刪除了。
后刪除token:網絡波動,業務復雜可能會出現這種情況:先處理業務,那么未刪除token前,前端再次點擊請求過來又將執行方法了。
復雜版本:token對應的value 有狀態,value 狀態為 1 是可提交,2是執行中,3是執行完成。點擊提交時一起發給后臺,同時前端將按鈕置灰,后臺驗證token以判斷后續流程。

## 版本號
數據庫增加數字類型的版本號字段,當讀取數據時,會將 version 字段的值一同讀出,更新時版本號加1,提交更新時會用當前數據里的版本號和數據庫中的版本號比對,如果不一致則表示有人修改過了。適合讀多寫少的業務。
## 唯一標識
優惠券重復領取:優惠券主鍵和用戶id做聯合唯一校驗,如果存在了則表示已領取
點贊:用戶id和被點贊id做聯合唯一校驗,如果存在了則表示已點贊
## 實際案例1(token解決表單重復提交)
非洲的后臺管理項目,那邊的網速比較慢,也沒有并發,就是網絡差
當時只是前端頁面按鈕加loading 效果的,沒使用token機制,超時之后,就又能點擊了,導致成功了倆條。
### 需要解決的問題
1. 接口冪等性問題
2. 用戶環境網速差,超時之后提交問題,單純token無法處理
### 解決方式
大概內容如下:細節記不清了
使用token:
前端進入表單頁面后, 向后臺請求一個唯一token,后臺以token為key放到redis中了(過期時間不要太短), value默認1, 用于在點擊提交時傳給后臺, 后臺通過此token在redis中的值來判斷是不是執行接口方法。 value有三個值, 1 初始值, 2 正在執行, 3 執行完成
第一次獲取token提交時, 在aop的前置通知里判斷token在redis中是否存在, 存在且等于1, 則將此token改為2,如果token 為2 則表示方法正在執行中, 如果為3, 表示方法已執行完成,也就是只有1時才繼續執行
在aop的后置返回通知(在目標方法返回之后執行)里,判斷返回的狀態碼是200嗎, 是修改value值為 3, 否則改為1.(因為有些參數校驗失敗, 也是在這里捕獲)
在aop的異常通知里修改value值為 1
這樣用戶第一次提交, value是1, 正常執行, 如果是超時以后, 方法value是2或者3就提示用戶相應信息。 如果第一次提交報錯了或者表單數據校驗沒通過, 那么value初始化為1了, 用戶再次點擊提交就相當于第一次提交
### 實際案例2 庫存更新
[電商庫存系統的防超賣和高并發扣減方案](https://xie.infoq.cn/article/741d651fdc8b4daf824fb8b31)
當時是訂單下單時預扣庫存,支付后才實際減庫存。鎖定庫存字段+真實庫存字段
#### MySQL直接更新
流量小,無并發,直接用java層面的鎖或者MySQL行鎖解決,減庫存是在一條sql里完成, 也會判斷庫存字段-具體扣減數>0才執行(就是update 表 庫存數量=庫存數量-具體扣減數 where 庫存數量-具體扣減數要>0)防止扣成負數,更新完成記錄流水日志
#### Redis + MySQL
先在redis中扣減, 在異步落庫
#### 實際案例3(唯一標識解決點贊)
使用唯一標識方式:用戶id和被點贊業務id做唯一標識
簡單版本:流量小且可以接受適度重復點贊。點贊后前端直接修改為不能點擊,后臺加鎖查詢下是否已點贊, 點贊和查詢都直接在數據庫。三無項目我們就這么應付, 這個可以實時顯示點贊數量, 開發簡單。
復雜:redis + mysql 在redis中點贊, 然后異步落庫(mq或者定時任務), 如果redis宕機,會有丟失數據風險
Redis 使用 set 類型, set集合有方法判斷 value 元素是否存在于集合 key 中(list沒有)
Key是業務標識:用戶id
value是 被點贊業務id 列表
```
// 視頻都有哪些用戶點贊 格式 video:likeuser:videoId1 userId1 userId2 userId3 userId4
sadd video:likeuser:videoId1 userId1 用戶1給視頻1點贊了
```
可以獲取當前用戶是否點贊(set可以判斷value是否在key中)、當前視頻點贊數量
// 用戶給哪些視頻點贊 這個根據業務確定是否需要
```
sadd video:userlike:userId1 videoId1 用戶1給視頻1點贊了
```
Set 支持取交集并集

- 學習地址
- MySQL
- 查詢優化
- SQL優化
- 關于or、in、not in、!=等走不走索引的說明
- 千萬級數據查詢優化
- MySQL 深度分頁問題
- 嵌套循環 Block Nested Loop 導致索引查詢慢
- MySQL增加日志統計表優化各種日志表的統計功能
- MySQL單機讀寫QPS(性能)優化
- sqlMode 置 select 的值可以比 group 里的多
- drop、delete、truncate的區別
- 尚硅谷MySQL數據庫高級學習筆記
- MySQL架構
- 事務部分
- MySQL知識點
- mysql索引
- Linux docker安裝 mysql 8.0.25
- docker 安裝mysql 5.7
- mysql Field ‘xxx’ doesn’t have a default value
- mysql多實例
- docker中的sql文件導入
- mysql進階知識
- mysql字符集
- 連接的原理
- redo日志
- InnoDB存儲引擎
- InnoDB的數據存儲結構
- B+樹索引
- 文件系統-表空間
- Buffer Pool
- 億級數據導入到es
- MySQL數據復制
- MySQL缺少主鍵的表數據
- mysql update 其中更新的字段根據另一個更新字段作為條件去更新
- MySQL指定字段值排序(將指定值排在前面)
- 設置MySQL連接數、時區
- Navicat15右鍵刪除數據刷新就又恢復了
- MySQL替換字段部分內容
- Java和MySQL統計本周本月本季和年
- 分頁時order by 排序數據重復,丟失
- mysql同一張表根據某個字段刪除重復數據
- mysqldump定時全量熱備
- 專題總結
- 事務
- MySQL事務
- spring事務
- spring事務本類調用
- spring事務傳播行為
- spring事務失效問題
- 鎖和Transactional注解一塊使用的問題
- 數據安全
- 敏感數據
- SQL注入
- 數據源
- XSS
- 接口設計
- 緩存設計
- 限流
- 自定義注解實現根據用戶做QPS限流
- 架構
- 高可用
- Java
- Unsatisfied dependency expressed through field ‘baseMapper‘
- mybatisplus多數據源
- 單個字母前綴的java變量
- spring
- spring循環依賴解決
- 事務@Transactional
- yml 文件配置信息綁定到java工具類的靜態變量上
- @Configuration @Component 區別
- springboot啟動yml文件報錯
- spring方法重試注解Retryable
- spring讀取yml集合數據
- spring自定義注解
- 獲取resource下的圖片資源
- 手機號和電話號的正則驗證
- 獲取字符串中的數字
- mybatis
- mybatis多參數添加數據并返回主鍵
- 統一異常處理
- 分組校驗
- Java讀取Python json.dumps 函數保存的redis數據
- springboot整合springCache
- 若依mybatis值為null的字段沒有返回
- 若依
- 接口白名單
- @JsonFormat時區問題
- RequestParam.value() was empty on parameter 0
- jdk8和hutool請求第三方的https報錯
- springMVC
- springMVC與vue使用post傳數組
- elementUI 時間組件報錯問題
- vue具名插槽slot
- springboot配置maven的profiles(配置微服務多環境切換打包)
- resources 配置文件讀取順序
- Windows的cmd部署jar注意事項
- Java基礎
- JUC(鎖-并發-線程池)
- CAS
- Java 鎖簡介
- synchronized和Logk有什么區別?用新的ock有什么好處
- synchronized鎖介紹
- CompletableFuture
- 多線程
- 線程池
- 集合類
- map見過的小問題
- 退出雙層循環
- StringBuilder和StringBuffer核心區別
- 日志打印
- 打印log日志
- log日志文件生成配置
- 日期時間
- 時間戳轉為時間
- 并發工具
- 連接池
- http調用
- 內網訪問天地圖
- 判等問題
- 數值計算
- null問題
- 異常處理
- 文件IO
- 序列化
- 內存溢出OOM
- Double轉String出現E的問題
- springboot接收前端表單提交多字段和上傳文件
- 子線程的錯誤, 全局異常處理捕獲不到
- vue同一個項目訪問多個不同ip地址接口
- Autowired注解導入為null
- shiro
- UnavailableSecurityManagerException錯誤
- Windows服務器80端口被占用
- java圖片增加水印
- springcloud
- Feign方法配置錯誤導致jar包啟動失敗
- feign調用超時
- Springcloud從Nacos的yml文件讀取出錯
- 定時任務quartz
- JavaPOI導出Excel
- 合并行和列
- 設置樣式
- 設置背景色
- docker
- Linux 安裝
- docker命令
- docker網絡
- docker數據卷
- dockerfile
- docker安裝ping命令
- docker-compose
- docker-compose文件內容介紹
- Linux關閉docker開機啟動
- jar打包為鏡像
- 遷移docker容器存儲位置
- Nginx
- Linux在線安裝Nginx
- nginx.conf 核心配置文件
- vue 和 nginx 刷新頁面會報404
- nginx 轉發給三個集群的tomcat
- ServerName匹配規則
- Nginx負載均衡策略
- location 匹配規則
- Nginx 搭建前端調用后臺接口的集群
- alias與root
- nginx 攔截 post 請求, 帶參數轉發到前端頁面
- 防盜鏈配置
- Nginx的緩存
- 通用Nginx配置
- nginx配置文件服務器
- 后臺jar包得不到正確ip,nginx代理時要處理
- 升級使用websocket協議
- 設置IP黑/白名單
- vue項目get請求Nginx返回html頁面post返回405錯誤
- Nginx限制所有接口流量
- Redis
- 緩存數據一致性
- 內存淘汰策略
- Redis數據類型
- gmt6
- Linux安裝GMT6
- GMT6配置中文
- GMT文件修改Windows版本到Linux版本
- 注意GMT不同字體導致符號不同的問題
- GMT繪制南海諸島小圖
- GMT生成中文圖例
- elasticsearch
- 安裝配置
- Linux安裝配置elasticsearch7.6.2
- Linux 安裝 kibana 7.6.2
- 安裝7.6.2中文分詞器
- docker 安裝elasticsearch7.6.2
- 安裝Logback7.6.2
- springboot使用
- 0. elasticsearch賬號密碼模式訪問
- 1. 配置連接
- 2. 索引
- 3. 批量保存更新
- Result window is too large 10000
- elasticsearch 分詞的字段做排序 fielddata, 設置fielddata=true 無效果
- elasticsearch 完全匹配查詢(精確查詢)
- 模糊搜索
- 日期區間查詢
- 6.x基礎知識
- 自定義詞庫
- elasticsearch集群
- 搜索推薦Suggester
- 查詢es保存的數組
- 億級mysql數據導入到es
- es 報錯 ORBIDDEN/12/index read-only
- es核心概念
- es的分布式架構原理
- 優化大數據量時的ES查詢性能
- canal
- 1. mysql的Binlog
- 2. Canal 的工作原理
- 3. canal同步es
- JVM
- 1 類的字節碼
- 2. 類的加載
- JVM知識點
- Maven
- 依賴沖突
- xxl-job
- docker 安裝配置 xxl-job
- idea
- springboot啟動報錯命令過長
- services統一啟動微服務各模塊
- 云服務器安裝寶塔面板
- 突然出現啟動或者運行特別慢
- 有導入依賴但是顯示紅色同時點擊進去也有依賴
- Linux
- sh文件執行報錯: command not found
- 使用vagrant安裝虛擬機
- Linux 開啟端口
- 開放端口
- 復制文件夾及其文件到另一個文件夾
- 兩個服務器之間映射端口
- TCP協議
- 分層模型
- TCP概述
- 支撐 TCP 協議的基石 —— 首部字段
- 數據包大小對網絡的影響 —— MTU 與 MSS 的奧秘
- 端口號
- 三次握手
- TCP 自連接
- 四次揮手
- TCP 頭部時間戳
- 分布式
- 分布式腦裂問題
- 分布式事務
- 基礎知識
- 實現分布式事務的方案
- 阿里分布式事務中間件seata
- 冪等性問題
- 其他工具
- webstorm git提交代碼后project目錄樹不顯示
- 消息隊列
- 如何保證消費的順序
- 數據結構
- 漫畫算法:小灰的算法之旅
- oracle