當(dāng)用數(shù)據(jù)庫存儲一個(gè)數(shù)值,并且這個(gè)數(shù)值需要被增減的時(shí)候,比如物品的數(shù)量。
在這種場景下,物品的數(shù)量是不能為負(fù)數(shù)的。那如何確保在扣減這個(gè)數(shù)量的時(shí)候,不會被扣成負(fù)數(shù)呢。
假設(shè)表數(shù)據(jù)如下:
sku | num |
a | 10 |
b | 20 |
假設(shè)現(xiàn)在 a 的 num 要 減少10個(gè)。
用程序在操作之前判斷? num 是否足夠扣減 ??這明顯是不靠譜的。因?yàn)橛胁l(fā)的情況存在。
在并發(fā)的情況下,a 的 num 會變成 -10 當(dāng)然,前提你的 sql 是這么寫的:
UPDATE table SET num=num-10 WHERE sku="a"
絕對不能用程序去計(jì)算 num 的值,在賦值到 sql 中,在并發(fā)情況下 ?num 會變成 0,錯誤示例:
$data = 'select * from table where sku="a"'; $num = $data['num'] - 10; UPDATE table SET num=$num WHERE sku="a"
所有的方案必須有正確的操作 sql 也就是,第一種 sql。
方案1:
利用數(shù)據(jù)庫的事務(wù),
在 update ?的 sql 執(zhí)行完成后,select num 的值判斷是否小于0,如果小于,回滾。
方案2:
更改 num 字段的屬性,無符號整形。
即字段屬性中的 ?UN,Unisigned
參考 sql :
ALTER TABLE `table` CHANGE COLUMN `num` `num` INT(11) UNSIGNED NOT NULL DEFAULT '0' ;
這種情況下,當(dāng) num 被減成負(fù)數(shù)的時(shí)候,數(shù)據(jù)庫會返回錯誤。
Error Code: 1690. BIGINT UNSIGNED value is out of range in ......
補(bǔ)上截圖