文章目錄
MySQL數據庫中的鎖
數據庫鎖的分類
- 按鎖的粒度劃分,可以劃分爲表級鎖、行級鎖、頁級鎖
- 按鎖的級別劃分,可分爲共享鎖、排它鎖
- 按加鎖的方式劃分,可分爲自動鎖、顯示鎖
- 按操作方式劃分,可分爲DML鎖、DDL鎖(其中增刪該查這一類的語句對應的爲DML鎖,而變動表結構這一類的操作爲DDL鎖)
- 按使用方式劃分,可分爲樂觀鎖,悲觀鎖
樂觀鎖:總是假設最好的情況,每次去拿數據的時候都認爲別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號機制和CAS算法實現。適用於多讀場景。
悲觀鎖:總是假設最壞的情況,每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖(共享資源每次只給一個線程使用,其它線程阻塞,用完後再把資源轉讓給其它線程)。傳統的關係型數據庫裏邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。Java中synchronized和ReentrantLock等獨佔鎖就是悲觀鎖思想的實現。適用於多寫場景。
MyISAM與InnoDB關於鎖方面的區別
MyISAM默認用的是表級鎖,不支持行級鎖
InnoDB默認用的是行級鎖,也支持表級鎖
MyISAM中
- 當進行SELECT時,會生成一個表級的讀鎖,此時若有UPDATE,INSERT,DELETE均會被BLOCK,陷入阻塞,直到讀鎖釋放。
- 同理,當進行UPDATE,INSERT,DELETE時,會生成一個表級的寫鎖,SELECT會被BLOCK,陷入阻塞直到寫鎖釋放。
手動爲表增加讀/寫鎖:
LOCK TABLES table_name read|write;
讀鎖:即共享鎖 ,因爲當已經有一個SELECT操作正在進行中時,此時對於同一張表再進行一個SELECT操作,第二個SELECT操作並不會被阻塞,而是正常執行,這個鎖可以被兩個SELECT操作所共享,所以也叫共享鎖。但是,當在第一個SELECT語句後面加上FOR UPDATE,即將其變成一個排他鎖,那麼此時若還有一個SELECT操作,則該操作會陷入阻塞
寫鎖:當已經有一個寫鎖時,此時若再設置一個寫鎖或者讀,都會陷入阻塞狀態。
InnoDB
InnoDB使用的是二段鎖,即加鎖和解鎖是分成兩個步驟:即先對同一個事務裏的一批操作進行加鎖,然後在commit時,再對加上的鎖進行統一的解鎖
由於在MySQL的InnoDB,事務默認是自動提交的,關閉事務的自動提交,可以用
SET autocommit = 0;
在InooDB中,對SELECT進行了優化,顯式得加上讀鎖應該在SELECT語句的後面加上 lock in share mode;InnoDB中鎖是默認支持行級的
在InnoDB中,sql沒有用到索引的時候使用的是表級鎖,用到索引的時候使用的是行級鎖
MySQL 數據庫中的死鎖
MyISAM不支持行級鎖,所以MySQL中的死鎖主要是在說InnoDB存儲引擎的死鎖。
MySQL中解決死鎖的兩種方式:通過業務和通過數據庫的設置
通過業務邏輯來解決死鎖問題
- 指定鎖的獲取順序
- 將大事務拆分成各個小事務
- 在同一個事務中,一次鎖定儘量多的資源,減少死鎖概率
- 給表建立合適的索引以及降低事務的隔離級別等
通過數據庫的設置來解決死鎖問題
- 通過參數 innodb_lock_wait_timeout 根據實際業務場景來設置超時時間,InnoDB引擎默認值是50s。
- 發起死鎖檢測,發現死鎖後,主動回滾死鎖鏈條中的某一個事務,讓其他事務得以繼續執行。將參數 innodb_deadlock_detect 設置爲 on,表示開啓這個邏輯(默認是開啓狀態)。
“行級鎖什麼時候會鎖住整個表?“
InnoDB行級鎖是通過鎖索引記錄實現的,如果更新的列沒建索引是會鎖住整個表的。
此處感謝一下牛客網,收穫很大。
MyISAM和InnoDB各自的適用場景
- MyISAM:
- 頻繁執行全表count語句,MyISAM中有一個變量保存了表的行數,所以很快
- 對數據進行增刪查的效率不高,查詢非常頻繁
- 沒有事務
- InnoDB:
- 數據的增刪改查都相當頻繁(通過行級鎖與表級鎖就能理解)
- 可靠性要求比較高,要求支持事務
MySQL數據庫中的事務
數據庫事務的四大特性
ACID
- 原子性(Automic):事務包含的所有操作要麼全部執行,要麼全部失敗回滾
- 一致性(Consistency):事務應確保數據庫的狀態從一個一致狀態轉變爲另外一個一致狀態。
- 隔離性(Isolation):多個事務併發執行時,一個事務的執行不該影響其他事務的執行
- 持久性(Durability):一個事務一旦提交,他對數據庫的提交應該永久保存在數據庫中。
事務併發訪問的問題以及事務隔離機制
事務的隔離級別
- 讀未提交(Read Uncommitted):
允許髒讀取。如果一個事務已經開始寫數據,則另外一個數據則不允許同時進行寫操作,但允許其他事務讀此行數據。
- 讀已提交(Read Committed):
允許不可重複讀取,但不允許髒讀取。讀取數據的事務允許其他事務繼續訪問該行數據,但是未提交的寫事務將會禁止其他事務訪問該行。
- 可重複讀(Repeatable Read):
禁止不可重複讀取和髒讀取,但是有時可能出現幻讀。讀取數據的事務將會禁止寫事務(但允許讀事務),寫事務則禁止任何其他事務。
- 序列化(Serializable):
提供嚴格的事務隔離。它要求事務序列化執行,事務只能一個接着一個地執行,但不能併發執行。
事務的隔離級別越高,對數據的完整性和一致性保證越佳,但是對併發操作的影響也越大。MySQL事務默認隔離級別是可重複讀。
事務併發訪問引起的問題以及如何避免
- 更新丟失:兩個不同事務同時獲得相同數據,然後在各自事務中同時修改了該數據,那麼先提交的事務更新會被後提交事務的更新給覆蓋掉,這種情況先提交的事務所做的更新就被覆蓋,導致數據更新丟失。(MySQL所有事務隔離級別在數據庫層面上均可避免)
- 髒讀:事務A讀取了事務B未提交的數據,由於事務B回滾,導致了事務A的數據不一致,結果事務A出現了髒讀(READ-COMMITED事務隔離級別以上可以避免,MySQL的InnoBD的默認隔離級別爲REPEATABLE_READ)
設置隔離級別:
SET SESSION TRANSACTION ISOLATION LEVEL read uncommited;
- 不可重複讀:一個事務在自己沒有更新數據庫數據的情況,同一個查詢操作執行兩次或多次得到的結果數值不同,因爲別的事務更新了該數據,並且提交了事務(REPEATABLE_READ事務隔離級別以上可以避免)
- 幻讀:事務A讀的時候讀出了N條記錄,事務B在事務A執行的過程中增加 了1條,事務A再讀的時候就變成了N+1條,這種情況就叫做幻讀。(設置爲SERIALIZABLE隔離級別即可避免,導致事務A看起來像出現幻覺一樣,這是最高隔離級別)
不可重複讀與幻讀的區別:幻讀是指一種結構上的改變,比如說條數發生了改變;不可重複讀是指讀出的數值發生了改變。
數據庫層面規避上述問題的具體總結見下表:
事務隔離級別 | 更新丟失 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|---|
未提交讀 | 避免 | 發生 | 發生 | 發生 |
已提交讀 | 避免 | 避免 | 發生 | 發生 |
可重複讀 | 避免 | 避免 | 避免 | 發生 |
串行化 | 避免 | 避免 | 避免 | 避免 |
出於性能考慮,事務隔離級別越高,安全性越高,串行化執行越嚴重,這樣會降低數據庫的併發度,因此需要根據業務去設置事務隔離級別
MySQL數據庫中兩大重要的日誌模塊
在MySQL的使用中,更新操作是很頻繁的,如果每一次更新操作都根據條件找到對應的記錄,然後將記錄更新,再寫回磁盤,那麼IO成本以及查找記錄的成本都會很高。所以,就出現了日誌模塊,也就是說,我們的update更新操作是先寫日誌,在合適的時間纔會去寫磁盤,日誌更新完畢就將執行結果返回給了客戶端。
binlog(歸檔日誌)
- bin log是Server層的日誌,所有引擎都可以使用
- binlog是邏輯日誌,記錄語句的原始邏輯,如 給uid=1這一行的數據賦新值"Bob",其中的statement形式,說白了本質也就是sql語句
- binlog是追加寫,一個日誌文件寫到一定大小後會切換到下一個,並不會覆蓋以前的日誌。
binlog日誌文件的格式(statement,row,mixed)
- statement格式的binlog記錄的是完整的SQL語句,優點是日誌文件小,性能較好,缺點也很明顯,那就是準確性差,遇到SQL語句中有now()等函數會導致不準確
- row格式的binlog中記錄的是數據行的實際數據的變更,優點就是數據記錄準確,缺點就是日誌文件較大。
- mixed格式的binlog是前面兩者的混合模式
目前大多數使用的是 row 模式,因爲很多情況下對準確性的要求是排在第一位的。
redo log(重做日誌)
- redo log是InnoDB引擎所特有的日誌模塊,是物理日誌,記錄了某個數據頁上做了哪些修改
- InnoDB的redo log是固定大小的,比如可以配置爲一組4個文件,每個文件的大小是1GB,那麼redo log總共就可以記錄 4GB的操作。從頭開始寫,寫到末尾就又回到開頭循環寫。
- InnoDB的redo log保證了數據庫發生異常重啓之後,之前提交的記錄不會丟失,這個能力稱爲crash-safe。
在下一篇MySQL的總結中會總結一下SQL語句中一些技巧,還有就是一個高頻面試點:慢查詢的sql調優以及一些其它瑣碎知識