問題描述
假設一個情況,這里只是假設,真實的情況可能不會這樣設計,但是假如真的發生了....鐵老大有一張這樣的ticket表,用來存放北京到上海的票。
iduidstart_addrend_addrbook_time
11300009860上海北京13866660321
20上海北京
30上海北京
40上海北京
uid?不等于0?并且?book_time?不等于0,則表示已售出,不許再更改。年底了,大家開始搶了,當某一個人開始搶的時候,鐵老大這樣做了,當A開始搶的時候,從表中所有uid=0的記錄中隨機取出一條,然后修改當前記錄的uid為A的uid,book_time為當前時間。那么好了,這個時候并發產生了,10000個人同時搶最后剩下的10張票,有2個人A,B同時讀取了uid=0?and?id=2的記錄,然后A把uid修改為自己的,book_time修改timeA,系統通知A搶票成功?緊接著,B同樣修改了這條記錄為自己的,那么這個時候A的票就失效了。這里就考慮使用鎖機制了,如果在A讀取了這條記錄后,并把這條記錄加上寫鎖,那么別人就無法再讀取加鎖,也就不會修改多次了。
實驗結果
實驗了一下for?update?加鎖,然后發現了一些問題。1、當我們使用主鍵查詢去加鎖的時候,可以對這條記錄加行鎖打開一個終端:執行一下代碼:mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from ticket where id = 2 for update;
那么?id=2這個記錄就會被加行寫鎖。令一個終端將無法讀取該記錄,但是卻可以讀取其他記錄#可以讀取加鎖
mysql> select * from ticket where id = 3 for update;
#不可以讀取
mysql> select * from ticket where id = 2 for update;
2、但是當我們按非主鍵查詢會怎樣呢mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from ticket where uid = 0 limit 1 for update;
那么這個時候,這個表會被鎖住,任何記錄都不能再讀取加鎖//不可讀取,等待釋放鎖
mysql> select * from ticket where id = 1 for update;
//不可讀取等待釋放鎖
mysql> select * from ticket where uid = 0 limit 1 for update;
但是表鎖會減少并發。
結論
有沒有一種方法,可以在非主鍵字段查詢一條記錄時上實現加行寫鎖,期待高手支招。