1、RDBMS數據組織
RDBMS中數據組織涉及到兩個最基本的結構:表與索引。表中存儲的是完整記錄,通常有兩種組織形式:堆表(全部的記錄無序存儲,如Oracle/DB2/PostgreSQL),或者是聚簇索引表(全部的記錄,按照記錄主鍵進行排序存儲,如InnoDB引擎)。索引中存儲的是完整記錄的一個子集,用於加速記錄的查詢速度,索引的組織形式,通常均爲B+樹結構。sql
2、RDBMS鎖的原則
2PL(二階段鎖Two-Phase Locking):傳統RDBMS加鎖的一個原則,就是2PL,說的是鎖操做分爲兩個階段:加鎖階段與解鎖階段,而且保證加鎖階段與解鎖階段不相交。下面以MySQL爲例,來簡單看看2PL在MySQL中的實現。數據庫
從上圖能夠看出,2PL就是將加鎖/解鎖分爲兩個徹底不相交的階段。加鎖階段:只加鎖,不放鎖。解鎖階段:只放鎖,不加鎖。因此JDBC Connection須要經過commit/rollback來提交或者釋放鎖。併發
3、MVCC
MySQL是一個支持插件式存儲引擎的數據庫系統。不一樣引擎的表現,會有較大的區別。InnoDB存儲引擎實現的是基於多版本的併發控制協議——MVCC (Multi-Version Concurrency Control) (注:與MVCC相對的,是基於鎖的併發控制,Lock-Based Concurrency Control)。post
MVCC最大的好處,讀不加鎖,讀寫不衝突。在讀多寫少的OLTP應用中,讀寫不衝突是很是重要的,極大的增長了系統的併發性能,這也是爲何現階段,幾乎全部的RDBMS,都支持了MVCC。性能
在MVCC併發控制中,讀操做能夠分紅兩類:快照讀 (snapshot read)與當前讀 (current read)。快照讀,讀取的是記錄的可見版本 (有多是歷史版本),不用加鎖。當前讀,讀取的是記錄的最新版本,而且,當前讀返回的記錄,都會加上鎖,保證其餘事務不會再併發修改這條記錄。優化
4、InnoDB一級索引、二級索引
每一個InnoDB表具備一個特殊的索引稱爲聚簇索引(也叫彙集索引,聚類索引,簇集索引)。若是表上定義有主鍵,該主鍵索引就是聚簇索引。若是未定義主鍵,MySQL取第一個惟一索引(unique)並且只含非空列(NOT NULL)做爲主鍵,InnoDB使用它做爲聚簇索引。若是沒有這樣的列,InnoDB就本身產生一個這樣的ID值,它有六個字節,並且是隱藏的,使其做爲聚簇索引。url
表中的聚簇索引(clustered index )就是一級索引,除此以外,表上的其餘非聚簇索引都是二級索引,又叫輔助索引(secondary indexes)spa
5、Mysql鎖
5.一、鎖的分類:.net
一、共享鎖(S鎖、讀鎖):容許併發的讀取同一資源, 但會阻塞其餘寫鎖的sql請求;插件
二、排他鎖(X鎖、寫鎖):一個寫鎖會阻塞其餘的寫鎖或讀鎖,保證同一時刻只有一個鏈接能夠寫入數據。
recordLock(行鎖):直接加在索引記錄上面,鎖住的是key,而非記錄自己(Oracle是經過在數據塊中對相應數據行加鎖來實現的)。若是該表上沒有任何索引,那麼Innodb會在後臺建立一個隱藏的聚簇索引,鎖住的就是這個隱藏的聚簇索引。即當一條sql沒有走任何索引時,那麼將會在每一條聚簇索引後面加X鎖,這個相似於表鎖,但原理上和表鎖應該是不一樣的。爲了效率考量,MySQL作了優化,對於不知足條件的記錄,會在判斷後放鎖,最終持有的,是知足條件的記錄上的鎖,可是不知足條件的記錄上的加鎖/放鎖動做不會省略。
gapLock(間隙鎖):鎖定索引記錄間隙,確保索引記錄的間隙不變。間隙鎖是針對事務隔離級別爲可重複讀或以上的。
next key lock:recordLock+gapLock
5.二、鎖的策略
一、row lock(行鎖):表中某些行被某個鏈接佔用了寫鎖,可是其餘行依然能夠被其餘鏈接請求讀鎖、寫鎖。
二、table lock(表鎖):整個表被某一個鏈接佔用了寫鎖,致使其餘鏈接的讀鎖或者寫鎖都會阻塞;影響整個表的讀寫。一般發生在DDL語句\DML不走索引的語句中。
6、Sql分析
select * from table where xxx; (MVCC快照讀,通常不加鎖)
select * from table where xxx lock in share mode; (讀鎖,當前讀,顯示鎖,會阻塞其餘的寫鎖請求,但其餘的讀鎖請求沒有影響)
select * from table where xxx for update; (寫鎖,當前讀,顯示鎖,會阻塞其餘的讀寫請求,)
update tableName set xxx (寫鎖,當前讀,隱式鎖)
insert (寫鎖,當前讀,隱式鎖)
delete (寫鎖,當前讀,隱式鎖)
說明:爲何將插入/更新/刪除操做,都歸爲當前讀?能夠看看下面這個更新操做,在數據庫中的執行流程:
一個Update操做的具體流程:當Update SQL被髮給MySQL後,MySQL Server會根據where條件,讀取第一條知足條件的記錄,而後InnoDB引擎會將第一條記錄返回,並加鎖 (current read)。待MySQL Server收到這條加鎖的記錄以後,會再發起一個Update請求,更新這條記錄。一條記錄操做完成,再讀取下一條記錄,直至沒有知足條件的記錄爲止。所以,Update操做內部,就包含了一個當前讀。同理,Delete操做也同樣。Insert操做會稍微有些不一樣,簡單來講,就是Insert操做可能會觸發Unique Key的衝突檢查,也會進行一個當前讀。
注:根據上圖的交互,針對一條當前讀的SQL語句,InnoDB與MySQL Server的交互,是一條一條進行的,所以,加鎖也是一條一條進行的。先對一條知足條件的記錄加鎖,返回給MySQL Server,作一些DML操做;而後在讀取下一條加鎖,直至讀取完畢。
7、Mysql事務
ANSI/ISO SQL標準定義了4中事務隔離級別:讀未提交(read uncommitted),讀提交(read committed),重複讀(repeatable read),串行讀(serializable)。不一樣的隔離級別有不一樣的現象:
一、髒讀(dirty read):一個事務能夠讀取另外一個還沒有提交事務的修改數據。
二、不可重複讀(nonrepeatable read):在同一個事務中,同一個查詢在T1時間讀取某一行,在T2時間從新讀取這一行時候,這一行的數據已經發生修改,可能被更新了(update),也可能被刪除了(delete)。
三、幻像讀(phantom read):在同一事務中,同一查詢屢次進行時候,因爲其餘插入操做(insert)的事務提交,致使每次返回不一樣的結果集。
不一樣的隔離級別有不一樣的現象,並有不一樣的鎖定/併發機制,隔離級別越高,數據庫的併發性就越差。在Oracle中默認的事務隔離級別是提交讀(read committed)。對於MySQL的Innodb的默認事務隔離級別是重複讀(repeatable read),Mysql中的RR不會髒讀、可重複讀(Innodb使用多版本一致性讀來實現),並不能徹底避免幻讀(這點和ANSI/ISO SQL標準定義的有所區別),須要加next key locks,可使顯示鎖(select * for update or lock in share mode)。
Ref: