一、MySQL邏輯架構
用戶端
連結/線程處理
查詢緩存
解析器
優化器
存儲引擎
二、鎖
1、讀寫鎖
讀鎖是共享的,是互相不阻塞的,多個客戶在同一時間讀取同一資源,互補幹擾。寫鎖是排他的,會阻塞其他的寫鎖和讀鎖,寫鎖有更高的優先級~
一種提高共享資源并發性的方式就是讓鎖定對象更有選擇性。盡量隻鎖定需要修改的部分資料,而不是所有的資源,鎖定的資源越少,系統的并發性更好。
表鎖(table lock)
表鎖是鎖開銷最小的政策,會鎖定整張表,一個使用者對表進行寫操作前,需要先獲得寫鎖,這會阻塞其他使用者對表的所有讀寫操作。舉例:有如下一張表
1
2
3
4
5
6
7
8
9
10
11
12
<code>CREATE</code> <code>TABLE</code> <code>`emp2` (</code>
<code> </code><code>`id` </code><code>int</code><code>(11) </code><code>NOT</code> <code>NULL</code> <code>DEFAULT</code> <code>'0'</code><code>,</code>
<code> </code><code>`</code><code>name</code><code>` </code><code>varchar</code><code>(100) </code><code>NOT</code> <code>NULL</code><code>,</code>
<code> </code><code>`job` </code><code>varchar</code><code>(100) </code><code>NOT</code> <code>NULL</code><code>,</code>
<code> </code><code>`num1` </code><code>int</code><code>(10) </code><code>DEFAULT</code> <code>NULL</code><code>,</code>
<code> </code><code>`num2` </code><code>int</code><code>(10) </code><code>DEFAULT</code> <code>NULL</code><code>,</code>
<code> </code><code>`num3` </code><code>int</code><code>(10) </code><code>DEFAULT</code> <code>NULL</code><code>,</code>
<code> </code><code>`job_num` </code><code>int</code><code>(10) </code><code>DEFAULT</code> <code>NULL</code><code>,</code>
<code> </code><code>`d` </code><code>date</code> <code>DEFAULT</code> <code>NULL</code><code>,</code>
<code> </code><code>PRIMARY</code> <code>KEY</code> <code>(`id`),</code>
<code> </code><code>KEY</code> <code>`job_num` (`job_num`)</code>
<code>) ENGINE=MyISAM </code><code>DEFAULT</code> <code>CHARSET=utf8 ;</code>
我們在一個終端中加上讀表鎖
<a href="http://blog.51cto.com/attachment/201310/105606537.png" target="_blank"></a>
然後打開另一個終端,可以讀但不可以寫
<a href="http://blog.51cto.com/attachment/201310/105742614.png" target="_blank"></a>
直到第一個連結釋放鎖之後,才能修改成功。
<a href="http://blog.51cto.com/attachment/201310/110043513.png" target="_blank"></a>
<a href="http://blog.51cto.com/attachment/201310/110119735.png" target="_blank"></a>
行級鎖:
行鎖可以最大程度的支援并發,但是鎖的開銷也最大,InnoDB支援行級鎖,在存儲引擎層實作。
死鎖:
兩個或者多個事務在同一資源上互相占用,并請求鎖定對方占用的資源時,導緻産生死鎖,比如有如下2個事務
<code>#事務1</code>
<code>start </code><code>transaction</code><code>;</code>
<code>update</code> <code>tab </code><code>set</code> <code>col=45 </code><code>where</code> <code>id = 4;</code>
<code>update</code> <code>tab </code><code>set</code> <code>col=54 </code><code>where</code> <code>id = 3;</code>
<code>commit</code><code>;</code>
<code>#事務2</code>
<code>update</code> <code>tab </code><code>set</code> <code>col=12 </code><code>where</code> <code>id = 3;</code>
<code>update</code> <code>tab </code><code>set</code> <code>col=18 </code><code>where</code> <code>id = 4;</code>
如果巧合,兩個事務都執行了第一條,更新了一行,同時鎖定了該行資料,接着都嘗試去執行第二條,卻發現被對方鎖定,然後2個事務都等待對方釋放鎖,則陷入死循環。為了解決這問題,資料庫系統實作了各種死鎖檢測和死鎖逾時機制。
2、隐式和顯式鎖定
隐式:InnoDB,在執行事務過程中會自動加鎖,除非執行COMMIT或ROLLBACK時鎖會自動釋放。
顯式:可以使用SELECT...LOCK IN SHARE MODE || SELECT...FOR UPDATE生成鎖
三、InnoDB的MVCC(多版本并發控制)
通過在每行記錄的最後儲存2個隐藏的列來實作。一個儲存行的建立時間,一個儲存行的過期時間,其實存的系統版本号。每開始一個新的事務,系統版本号都會遞增。事務開始時刻的系統版本号作為事務的版本号,用來和查詢到的每行記錄的版本号來比較。
SELECT:
InnoDB會根據以下2個條件檢查每行記錄:
a、隻查找版本早于目前事務版本的資料行,也就是行的系統版本号小于或等于事務的系統版本号,這樣可以確定事務讀取的行,要麼是在事務開始前已經存在的,要麼是事務自身插入或修改的。
b、行的删除版本要麼未定義,要麼大于目前事務版本号。這樣可以確定事務讀取到的行在事務開始之前未被删除。
INSERT:
InnoDB為新插入的每一行儲存目前系統版本号為行版本号
DELETE:
InnoDB為删除的每一行儲存目前系統版本号作為行的删除标示。
UPDATE:
InnoDB為插入一行新紀錄,儲存目前系統版本号作為行版本号,同時儲存目前系統版本号到原來的行作為行删除标示。
儲存這2個額外的系統版本号,使大多數讀操作都可以不用枷鎖。這樣資料庫操作簡單,性能也會很好,并且保證隻會讀到标準的行。但是需要額外的空間和更多的檢查工作。
本文轉自shayang8851CTO部落格,原文連結:http://blog.51cto.com/janephp/1306411,如需轉載請自行聯系原作者