舉一個最經典的庫存超賣的問題,假設一條資料是這樣。
id ,商品名 ,庫存 這樣的一張表結構
id product_sku inventory
1 SKU-1 10
看了下很多網上博客說,一種常用的方式是加悲觀鎖 或者 樂觀鎖。
實作方式大概是:一開始就加讀鎖 :for update ,其他事務只能阻塞等待當前事務提交,才能再在這行資料上加讀鎖
樂觀鎖加一個版本號欄位作為,update 提交時候檢測當前事務在此程序中,有無其他行程修改了當前資料,若修改了則失敗
我的理解是比如:
行程一:
select inventory from table where id=1 for update;
查出 inventory;
然后 $inventory = 9;
update set inventory= 9 WHERE id=1;
commit;
此時 update 是直接賦值。
加入 update 時候 直接 update set inventory= inventory-1 ,不就根本不需要加行鎖嗎?
因為 update 陳述句本身不就是會加 排它鎖嗎?
最簡單的實作方式直接:
行程一: begin; update set inventory= inventory-1 WHERE id=1;
行程二:begin; update set inventory= inventory-2 WHERE id=1;
此時行程一是update 操作,有排它鎖鎖行,行程二直接阻塞。
等待行程一提交事務,釋放鎖,行程二再執行。
這樣不就已經解決超賣問題了嗎?為啥還需要用 for update 來實作呢?
不是更簡單解決?
求大神解決。
uj5u.com熱心網友回復:
需要用戶寫顯式事務, 一般是業務比較復雜一點的場景, 你沒有領會到其中的關鍵點。用銀行取款來說比較容易理解。
如果你有1000元的存款,然后:
A. 你在手機銀行上轉賬600元,
B. 你女友拿了你的銀行卡,在ATM機上取款600元。
A、B 兩個操作,單獨執行都是沒有問題,但一起執行就有問題了。
事務,就是為了避免這種問題發生而產生的。
你設想一下,我上面所說的場景,不用事務來實作,能做到嗎?
uj5u.com熱心網友回復:
我知道你的意思,,,我的以上操作都是加了事務的前提。
余額欄位設定不能為負數。
比如我取600,
事務一:
begin;
update table set account = account-600 WHERE id = 1;
未提交事務。
女朋友取錢600,
事務二:
begin;
update table set account = account-600 WHERE id = 1 and account > 0;
事務一未提交,事務二阻塞等待,等事務一提交之后,才會執行事務二的操作、
此時根本不會出現多扣的情況啊。
為什么要用樂觀鎖,加版本號的方式?
難道是因為冪等??比如重復提交?
uj5u.com熱心網友回復:
簡單的情況, 如你這樣是可以的。再復雜一點就不行了。
比如:還要拿到這個id, 再對相關表做操作,對關聯賬戶做增加余額。
除了這種情況, 還有一種兩個用戶同時進入修改一個記錄的情況, 這也是比較常見的。
即使沒有競爭, 也要考慮到。
比如:兩個領導同時修改某一個員工的工資,
領導1 先將此人工資由 2000 改到 5000
領導2 再將此人工資由 2000 改到 5500
如果直接允許兩者修改,其實領導2是沒有見到領導1修改的值,因為兩人進入頁面的時間差不多, 只是提交的時間不同而已。
如果領導2 知道有人改過這個人的工資, 很可能就不會再改了。
這種情況, 用時間戳作為版本號是非常合理的。
領導2在后提交時, 時間戳變化了直接提示一下記錄已變更過,再退到上一級頁面就可以了。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/41498.html
標籤:疑難問題
上一篇:DVWA出錯
下一篇:sql配置管理器里,TCP/IP協議開啟以后,SQL SERVER(MSSQLSERVER)服務就無法啟用,怎么辦?
