MyISAM存儲引擎:開銷小,加鎖快,無死鎖。鎖定粒度大,併發度低,容易發生鎖衝突。 不支持事務。 採用表鎖 (操做時對操做的表上鎖) 基本不用了java
innoDB存儲引擎:開銷大,有死鎖,鎖定粒度小,不容易發生衝突。 採用行鎖(每句sql執行時對操做行上鎖),可是也支持表鎖 mysql默認引擎mysql
問題:庫存超賣linux
庫存1,結果兩我的同時購買,第一我的判斷後還有1個剩餘,因而執行 update 操做, 這時第二我的開始判斷,此時update還沒結束,剩餘仍是1,因而也開始進update操做,致使庫存變爲-1.sql
1. 悲觀鎖,在判斷的select語句中加入行鎖,與update語句互斥,保證第1我的提交事務前,第2我的不能操做這個貨物。數據庫
2.樂觀鎖,添加版本字段,查詢時更新版本字段,版本字段變化時,不能更新。安全
select num, version from warehouse where id = 商品編號; 查詢數量同時查出版本,好比111併發
update warehouse set num = num - 1, version = version + 1 where version = 111; 這樣假如warhouse在查詢後這個商品被更改過,這條將不會更改任何字段。若是成功了版本同時改變爲112。編輯器
reference: http://www.zsythink.net/archives/1233/測試
事務隔離:spa
讀未提交: read-uncommitted 可能問題:髒讀,幻讀,不可重複讀 A修改操做後沒有提交,B也能看到改動
讀已提交:read-commited 可能問題:幻讀,不可重複讀 A修改操做後提交了,B能夠看到改動
可重複讀: repeatable-read 可能問題:不可重複讀 A修改操做後,B的操做也用到了相同的表後能夠看到A的改動
可序列化:serialiazable 三種都不會出現 A修改操做時,B連讀取都作不到。 這樣最安全,可是沒法併發,效率過低。
髒讀: 讀到了別人未提交的改動 (表的數據實際沒有變化,可是你覺得變了) B修改了數據還沒提交,A查到了,B的數據提交失敗回滾了,A覺得B改完了。
幻讀: 數量不對 ( 表的數據數量變化) A在查詢後, B添加或者刪除了數據, A覺得數據沒變。
不可重複讀: 讀取和修改時狀態不一致 (數據值發生變化) A在查詢後,B修改了數據值,A仍是以舊數據做爲判斷條件。
不可重複讀 和 幻讀差很少,不過一個是莫名其妙多了一行,一個是莫名其妙值變了。 因此庫存超賣是不可重複讀。
1.
查詢數據庫事務隔離等級:
SHOW VARIABLES LIKE '%isolation'; #網上查的版本是tx_isolation, 個人版本是 transaction_isolation,因此直接用模糊查詢
通常都是 可重複讀級別
2.修改隔離等級:
SET transaction_isolation = 'read-uncommitted';
mysql的鎖: 表名 index_test
1. 查看錶存儲引擎
SHOW TABLE STATUS LIKE 'index_test';
2. 修改表存儲引擎
ALTER TABLE index_test ENGINE = MYISAM; #修改表引擎 SHOW TABLE STATUS LIKE 'index_test';
3. 表鎖
表鎖有讀鎖,和寫鎖
讀鎖:不讓其餘鏈接修改表, 是能夠查詢的!
寫鎖:不讓其餘鏈接查詢和修改表。
- -|||注意別隻憑字面意思理解,有時候容易形成讀鎖是不讓讀,寫鎖是不讓寫的錯覺(好比我。。。)
1).對index_test 添加表寫鎖 (這時在當前數據庫鏈接會話下是能夠修改表的。)
LOCK TABLE index_test WRITE;
2). 新建一個數據庫鏈接(文件 -> 新連接 不是新打開一個查詢編輯器或者窗口= =sqlyog打開新窗口仍是用的同一個連接。。。)
而後修改index_test表 (查詢也是同樣的結果)
能夠看到 會一直顯示處理中。
3).這時在第一個鏈接中解鎖表
UNLOCK TABLES;
發現第二個鏈接的修改語句馬上執行完畢。
我的測試(我有一個大膽的想法):
創建鏈接a,b,c
a鎖表
b修改 - 進入等待
c輸入解鎖
b依舊等待
c鎖表 - 進入等待
a解鎖 - b執行完畢,c執行完畢
a鎖表 - 進入等待。。。由於c把表鎖了
c解鎖
能夠得出結論:不一樣的鏈接的鎖表和解鎖是獨立的。。。
4).對index_test 添加表讀鎖 (這時在當前數據庫鏈接會話下是能夠修改表的。)
LOCK TABLE index_test READ;
這時第二個鏈接,修改時會進入等待狀態,可是能夠查詢。
4. 行鎖
myisam 只有表級鎖,因此要切換回innodb
行鎖:執行語句時,只鎖住相關數據行,而不是整個表。 這也是innodb能支持事務的主要緣由之一。(要是鎖表,那麼一次事務中用到多個表的時候,會致使數據庫不少表被鎖,大幅拖慢效率)
innodb會自動給修改語句添加行鎖。
1. 修改表引擎
ALTER TABLE index_test ENGINE = INNODB;
2.取消自動提交(innodb會把單獨的sql語句做爲事務直接提交,取消後必須commit才能提交一次事務)
SET autocommit = 0;
3. 進行一次修改
UPDATE index_test SET key1 = 1 WHERE t_id = 1;
新建鏈接2,對錶進行修改
UPDATE index_test SET key1 = 3 WHERE t_id = 1;
鏈接2 進入等待
過一段時間後提示超時
鏈接1 提交修改
COMMIT;
鏈接2 再次嘗試修改,成功
我的測試:既然是行鎖,那麼嘗試在鏈接2修改不一樣行的數據看看結果-。-
鏈接1:
UPDATE index_test SET key1 = 1 WHERE t_id = 1;
鏈接2:
UPDATE index_test SET key1 = 3 WHERE t_id = 2;
鏈接2直接修改爲功。
5.爲查詢語句添加行鎖
悲觀鎖解決庫存超賣問題:
悲觀鎖,在判斷的select語句中加入行鎖,保證第1我的提交事務前,第2我的不能操做這個貨物。
用index_test 表做爲例子
t_id = 1這一行中, key = 1。假設爲key1 是一種貨物,剩餘1個
a 進行查詢,同時上行鎖,準備更新
SELECT * FROM index_test WHERE t_id = 1 FOR UPDATE;
b此時開始查詢
SELECT * FROM index_test WHERE t_id = 1 FOR UPDATE;
產生讀讀互斥,b進入等待,等待a提交。
a更新並提交
UPDATE index_test SET key1 = key1 - 1 WHERE t_id = 1; COMMIT;
a提交後,b查出結果
key1已經變成了0
從而避免了庫存超賣。
死鎖:
和java的差很少。。。
a:查詢A,上鎖A, 等查到後修改B, 而後提交
b:查詢B,上鎖B, 等查到後修改A, 而後提交
對於a,須要修改B才能提交事務,而後解鎖A。
對於b,須要修改A才能提交事務,而後解鎖B。
造成死鎖。
彼此佔用鑰匙。
解決:kill掉其中一個線程。(圖形界面好比sqlyog中直接點個x就完事了。。。不過linux開發有時要用名命令行的那種 - -)