-- P1, P2 get the same balance P1: SELECT balance FROM wallet_tab WHERE wallet_id=$wallet_id; (balance=100) P2: SELECT balance FROM wallet_tab WHERE wallet_id=$wallet_id; (balance=100)
-- P1 update first, then P2 update P1: UPDATE wallet_tab SET balance=balance-20 WHERE wallet_id=$wallet_id; P2: UPDATE wallet_tab SET balance=balance-30 WHERE wallet_id=$wallet_id;
-- balance is updated to 70, but it should be 50.
悲观行锁 - TCC
为了支持TCC,可以稍微调整表结构,示例如下:
1 2 3 4 5 6 7 8 9 10 11 12
-- 用户钱包表 CREATE TABLE `wallet_tab` ( `wallet_id` bigint(20) unsigned NOT NULL, `wallet_type` tinyint(3) unsigned NOT NULL, `user_id` bigint(20) unsigned NOT NULL, `balance` bigint(20) NOT NULL, `frozen` bigint(20) NOT NULL, -- 新增字段,存储冻结的金额 `create_time` bigint(20) unsigned NOT NULL, `update_time` bigint(20) unsigned NOT NULL, PRIMARY KEY (`wallet_id`), UNIQUE KEY `uniq_user_id_wallet_type` (`user_id`, `wallet_type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
// try SELECT balance FROM wallet_tab WHERE uid=$uid forUpdate UPDATE wallet_tab SET balance=$balance-20, frozen=$frozen+20where wallet_id=$wallet_id;
// confirm SELECT balance FROM wallet_tab WHERE uid=$uid forUpdate UPDATE wallet_tab SET frozen=$frozen-20where wallet_id=$wallet_id;
// cancel SELECT balance FROM wallet_tab WHERE uid=$uid forUpdate UPDATE wallet_tab SET balance=$balance+20, frozen=$frozen-20where wallet_id=$wallet_id;;