您好,登錄后才能下訂單哦!
本篇文章為大家展示了如何使用 Laravel sharedLock 與 lockForUpdate 進(jìn)行數(shù)據(jù)表行鎖,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。
拼團(tuán)功能,當(dāng) A 客戶開(kāi)團(tuán)之后(兩人團(tuán)),如果 B 和 C 同時(shí)支付,如何規(guī)避兩人同時(shí)將拼團(tuán)人數(shù)增加。
sharedLock 對(duì)應(yīng)的是 LOCK IN SHARE MODE
lockForUpdate 對(duì)應(yīng)的是 FOR UPDATE
sharedLock 與 lockForUpdate 相同的地方是,都能避免同一行數(shù)據(jù)被其他 transaction 進(jìn)行 update。
不同的地方是:
sharedLock 不會(huì)阻止其他 transaction 讀取同一行
lockForUpdate 會(huì)阻止其他 transaction 讀取同一行 (需要特別注意的是,普通的非鎖定讀取讀取依然可以讀取到該行,只有 sharedLock 和 lockForUpdate 的讀取會(huì)被阻止。)
即 sharedLock locks only for write, lockForUpdate also prevents them from being selected
這樣做是有意義的,例如,兩個(gè) transaction 要更新同一個(gè)計(jì)數(shù)器,如果不使用 lockForUpdate, 會(huì)導(dǎo)致兩個(gè) transaction 同時(shí)讀到同一個(gè)初始值,然后在應(yīng)用層邏輯中增加計(jì)數(shù)之后,提交到數(shù)據(jù)庫(kù)中,后者的操作會(huì)覆蓋掉前者的操作。
在 MySQL 命令行終端操作一個(gè)表
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from users for update;
+----+------+
| id | name |
+----+------+
| 1 | tom |
| 2 | bob |
+----+------+
這時(shí)再開(kāi)一個(gè)命令行終端
mysql> select * from users for update;
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> select * from users lock in share mode;
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
你會(huì)發(fā)現(xiàn),無(wú)論是 for update 還是 lock in share mode 都無(wú)法讀取到數(shù)據(jù),更加確切地說(shuō)是,查詢被阻塞了。
只有在第一個(gè)終端執(zhí)行
commit;
第二個(gè)終端才能得到數(shù)據(jù)返回。
需要注意的是,發(fā)起者必須在 transaction 里上鎖才有效,如果不是在 transaction 中,上鎖是無(wú)效的。但是,第二個(gè)人無(wú)論是不是在 transaction 里,都會(huì)被鎖。
Laravel 如何設(shè)置數(shù)據(jù)庫(kù)操作超時(shí)時(shí)間
什么場(chǎng)景下適合使用 sharedLock 呢?
sharedLock,lockForUpdate 與 Pessimistic Locking 是什么關(guān)系
Pessimistic locking(悲觀鎖) 與 Optimistic locking(樂(lè)觀鎖)的區(qū)別
A 用戶,在瀏覽器里訪問(wèn)接口 (模擬支付回調(diào)),此時(shí)對(duì)數(shù)據(jù)表中某一行鎖住,進(jìn)行 30s 操作,然后提交事務(wù)。
B 用戶,在瀏覽器里訪問(wèn)同一接口 (模擬支付回調(diào)),其無(wú)法修改該行。對(duì)應(yīng)的返回是什么?
會(huì)一直 wait 到數(shù)據(jù)庫(kù)操作超時(shí)。
那么問(wèn)題來(lái)了,Laravel 如何設(shè)置數(shù)據(jù)庫(kù)操作超時(shí)時(shí)間?
簡(jiǎn)單的測(cè)試方法,是在命令行中開(kāi)兩個(gè) artisan tinker 窗口,分別執(zhí)行
DB::transaction(function () {
echo 1;
User::where('id', 33)->lockForUpdate()->get();
echo 2;
sleep(10);
});
你會(huì)發(fā)現(xiàn)第二個(gè) tinker 窗口中的 get 操作,需要等到第一個(gè) transaction 執(zhí)行完畢之后,才能得到查詢結(jié)果。
需要注意的是,不在 transaction 中的 lockForUpdate 操作,是沒(méi)有鎖效果的。
真實(shí)場(chǎng)景,防止用戶重復(fù)提現(xiàn)
DB::transaction(function () use ($user, &$user_award) {
$user_award = UserAward::where([
['user_id', $user->id],
['status', 0],
])
->lockForUpdate()
->first();
if ($user_award) {
$user_award->status = 1; // 提現(xiàn)中狀態(tài)
$user_award->save();
}
});
if (!is_null($user_award)) {
$amount = $user_award->money * 100;
}
事務(wù)中涉及的操作都會(huì)加上鎖?
如果默認(rèn)會(huì)加上鎖,那么默認(rèn)會(huì)加上什么鎖呢?
事務(wù)中涉及的操作,不需要顯式加鎖?
要理清其中關(guān)系,就需要了解事務(wù)的四種隔離級(jí)別:
未提交讀(Read uncommitted)
已提交讀(Read committed)
可重復(fù)讀(Repeatable read)
可串行化(Serializable )
MySQL 默認(rèn)的是:可重復(fù)讀(Repeatable read)
上述內(nèi)容就是如何使用 Laravel sharedLock 與 lockForUpdate 進(jìn)行數(shù)據(jù)表行鎖,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。