狀態標記(業務鎖)實現方案
單據數據污染解決方案-狀態標記(業務鎖)
單據數據污染解決方案-狀態標記(業務鎖)
感覺本篇對你有幫助可以關注一下我的微信公眾號(深入淺出談java),會不定期更新知識和面試資料、技巧!!!

如何防止單據數據被多人操作,造成數據污染?
確保同一時間只有一個用戶可以編輯單據,或者至少能檢測到并發修改,避免數據沖突。比如當用戶嘗試編輯一個被鎖定的單據時,提示“當前單據正被其他用戶編輯”。同時,在服務端處理并發請求時,確保更新狀態的原子性,避免競態條件。
這時候,我應該考慮常見的并發控制方法。比如樂觀鎖和悲觀鎖,這兩種方法在開發中經常用到。
本文主要針對的是 狀態標記(業務鎖)
解決方案
常見的解決方案包括:
- 樂觀鎖:通過版本號或時間戳檢測沖突。
- 悲觀鎖:在事務中使用行級鎖。
- 狀態標記:結合超時機制防止死鎖。
- 前端提示和實時檢測。
- 操作日志和版本比對。
- 分布式鎖應對多實例環境。
- 權限控制減少沖突可能性。
需要根據具體場景選擇合適的方案,或者組合使用多種方法。例如,使用樂觀鎖處理大部分情況,結合前端提示和狀態標記來提升用戶體驗。或者在高并發場景下使用悲觀鎖,同時設置合理的超時時間。
其他解決辦法可閱讀:單據污染解決方案 - 古渡藍按 - 博客園
流程圖

核心邏輯
狀態標記。在單據表中增加一個狀態字段,比如“編輯中”,當用戶開始編輯時,將狀態設為不可編輯,保存后再恢復。這種方法需要前端和后端配合,比如用戶點擊編輯時,后端檢查狀態是否為可編輯,如果是,就設為編輯中,防止其他人編輯。但可能存在用戶忘記保存或者異常退出的情況,導致狀態一直處于編輯中,所以可能需要一個超時機制,自動釋放狀態。
狀態標記(業務鎖)核心邏輯
通過業務字段標記單據的編輯狀態,確保同一時間只有一個用戶能操作單據。
關鍵點:
- 使用數據庫字段(如
status)標記單據是否被鎖定。 - 用戶嘗試編輯時,檢查并搶占鎖;編輯完成后釋放鎖。
- 超時機制:防止用戶未提交導致鎖永久占用。
具體實現步驟
1. 數據庫設計
例如:在單據表中添加字段
| 字段名 | 類型 | 說明 |
|---|---|---|
status |
int | 0-可編輯,1-編輯中 |
lock_by |
varchar | 鎖定者(用戶ID) |
lock_time |
datetime | 鎖定時間(用于超時釋放) |
2. 用戶操作流程
| 步驟 | 用戶行為 | 前端 | 服務端邏輯 | 數據庫操作 |
|---|---|---|---|---|
| 1 | 用戶A點擊“編輯”按鈕 | 發送/lock請求,攜帶單據ID |
檢查當前單據狀態: 若status=0,更新為status=1,記錄lock_by和lock_time |
UPDATE table SET status=1, lock_by='A', lock_time=NOW() WHERE id=123 AND status=0 |
| 2 | 用戶A編輯表單 | 表單展示,禁用其他用戶操作入口 | 保持鎖定狀態 | 無 |
| 3 | 用戶A提交保存 | 發送保存請求,攜帶修改數據 | 更新單據數據,并釋放鎖(status=0) |
UPDATE table SET ..., status=0 WHERE id=123 AND lock_by='A' |
| 4 | 用戶B嘗試編輯同一單據 | 發送/lock請求 |
檢查狀態:status=1,返回“單據已 |
超時釋放鎖
-
后臺定時任務:每隔N分鐘掃描
lock_time超時的單據,自動釋放鎖:UPDATE table SET status=0 WHERE status=1 AND lock_time < NOW() - INTERVAL '5 MINUTE';
偽代碼
1. 服務端鎖定邏輯(偽代碼)
def lock_order(order_id, user_id):
# 原子操作:嘗試鎖定
updated = execute_sql(
"UPDATE orders SET status=1, lock_by=%s, lock_time=NOW() "
"WHERE id=%s AND status=0",
[user_id, order_id]
)
if updated == 0:
# 獲取當前鎖定者信息
locked_by = execute_sql(
"SELECT lock_by FROM orders WHERE id=%s", [order_id]
)
return {"success": False, "message": f"單據已被{locked_by}占用"}
return {"success": True}
2. 前端提示邏輯(偽代碼)
// 用戶點擊編輯按鈕
async function handleEdit(orderId) {
const res = await fetch('/lock', { method: 'POST', body: { orderId } });
if (!res.success) {
alert(res.message); // 如“單據已被張三鎖定”
} else {
// 進入編輯模式
}
}
注意事項
- 原子性:鎖定操作需通過單條SQL保證原子性(避免競態條件)。
- 鎖釋放:
- 用戶提交后必須釋放鎖。
- 異常場景(如用戶關閉頁面)依賴后臺超時釋放。
- 用戶體驗:
- 前端可輪詢檢查鎖狀態(如每30秒查詢一次)。
- 提示具體鎖定者(如“單據正被張三編輯”)。
通過狀態標記機制,可低成本實現多人操作沖突控制,適合中小型系統或業務流程明確的場景。
最后文章有啥不對,歡迎大佬在評論區指點!!!
如果感覺對你有幫助就點贊推薦或者關注一下吧!!!


浙公網安備 33010602011771號