MySQL 中常見的日志有哪些?是如何實現事務的?
MySQL 中常見的日志有哪些?
MySQL日志主要包括查詢日志、慢查詢日志、事務日志、錯誤日志、二進制日志等。其中比較重要的是 bin log(二進制日志)和 redo log(重做日志)和 undo log(回滾日志)。
bin log
bin log是MySQL數據庫級別的文件,記錄對MySQL數據庫執行修改的所有操作,不會記錄select和show語句,主要用于恢復數據庫和同步數據庫。
redo log
redo log是innodb引擎級別,用來記錄innodb存儲引擎的事務日志,不管事務是否提交都會記錄下來,用于數據恢復。當數據庫發生故障,innoDB存儲引擎會使用redo log恢復到發生故障前的時刻,以此來保證數據的完整性。將參數innodb_flush_log_at_tx_commit設置為1,那么在執行commit時會將redo log同步寫到磁盤。
undo log
除了記錄redo log外,當進行數據修改時還會記錄undo log,undo log用于數據的撤回操作,它保留了記錄修改前的內容。通過undo log可以實現事務回滾,并且可以根據undo log回溯到某個特定的版本的數據,實現MVCC。
bin log和redo log有什么區別?
bin log會記錄所有日志記錄,包括InnoDB、MyISAM等存儲引擎的日志;redo log只記錄innoDB自身的事務日志。bin log只在事務提交前寫入到磁盤,一個事務只寫一次;而在事務進行過程,會有redo log不斷寫入磁盤。bin log是邏輯日志,記錄的是SQL語句的原始邏輯;redo log是物理日志,記錄的是在某個數據頁上做了什么修改。
bin log 有哪些日志類型?
binlog 有 3 種格式類型,分別是 STATEMENT(默認格式)、ROW、 MIXED,區別如下:
- STATEMENT:每一條修改數據的 SQL 都會被記錄到 binlog 中(相當于記錄了邏輯操作,所以針對這種格式, binlog 可以稱為邏輯日志),主從復制中 slave 端再根據 SQL 語句重現。但 STATEMENT 有動態函數的問題,比如你用了 uuid 或者 now 這些函數,你在主庫上執行的結果并不是你在從庫執行的結果,這種隨時在變的函數會導致復制的數據不一致;
- ROW:記錄行數據最終被修改成什么樣了(這種格式的日志,就不能稱為邏輯日志了),不會出現 STATEMENT 下動態函數的問題。但 ROW 的缺點是每行數據的變化結果都會被記錄,比如執行批量 update 語句,更新多少行數據就會產生多少條記錄,使 binlog 文件過大,而在 STATEMENT 格式下只會記錄一個 update 語句而已;
- MIXED:包含了 STATEMENT 和 ROW 模式,它會根據不同的情況自動使用 ROW 模式和 STATEMENT 模式;
注意:不同的日志類型在主從復制下除了有動態函數的問題,同樣對對更新時間也有影響。一般來說,數據庫中的update_time都會設置成ON UPDATE CURRENT_TIMESTAMP,即自動更新時間戳列。在主從復制下:
如果日志格式類型是STATEMENT,由于記錄的是sql語句,在salve端是進行語句重放,那么更新時間也是重放時的時間,此時slave會有時間延遲的問題;
如果日志格式類型是ROW,這是記錄行數據最終被修改成什么樣了,這種從庫的數據是與主服務器完全一致的。
什么是 Write-Ahead Logging (WAL)技術?它的優點是什么?MySQL 中是否用到了 WAL?
WAL(Wite-Ahead Logging)技術是一種數據庫事務日志管理技術,它確保在修改真正的數據之前,先將修改記錄寫入日志,這使得即使系統崩潰,通過日志也能恢復教據,保證了數據的特久性和一致性
WAL它的核心思想就是先寫日志,再寫數據,大致執行流程如下:
- 當一個事務開始時,所有對數據庫的修改都會先記錄到一個日志文件中,而不是直接應用到數據庫文件,這些日志記錄了數據的變更信息,可以用于恢復數據.。
- 當日志記錄被安全地寫入磁盤后,才會將這些修改應用到數據庫文件中。
在 MySQL InnoDB 存儲引擎中,重做日志 (Redo Log)就是 WAL的實現,用于保證事務的持久性和崩潰恢復能力。InnoDB 重做日志的工作機制如下:
- 當一個事務開始時,所有對數據庫的修改首先記錄到重做日志緩沖區中。
- 重做日志緩沖區的數據會周期性地刷新到磁盤上的重做日志文件(ib_logfile0和ib_logfile1)。
- 當事務提交時,InnoDB 確保重做日志已寫入磁盤,然后將數據頁的修改寫入數據文件。
- 如果系統崩潰,InnoDB 會在啟動時通過重做日志重新應用所有未完成的事務,以恢復數據庫到一致狀態。
MySQL插入一條 SQL 語句,redo log 記錄的是什么?
因為 redo log 是物理日志,記錄“某頁(Page)某位置的數據被修改為某值”。它不記錄邏輯操作(如“插入一行”,而是直接記錄對頁的變更。所以在插入操作中,redolog 記錄的是事務在數據頁上的修改
數據頁的插入點、記錄的偏移量和插入的實際數據并更新頁目錄、頁頭等元數據
插入操作 redo log 具體執行流程
- 修改緩沖頁(Buffer Pool):數據先寫入內存中的緩沖池,而不是直接寫入磁盤.
- 生成 redo log:同時生成一條 redo log,記錄插入對數據頁的物理修改細節。
- 日志先行(Write-Ahead Logging, WAL):redo log 先被寫入磁盤上的 redo log 文件。
MySQL的binlog有幾種格式?分別有什么區別?
有三種格式,statement,row和mixed。
- statement:每一條會修改數據的sql都會記錄在binlog中。不需要記錄每一行的變化,減少了binlog日志量,節約了IO,提高性能。由于sql的執行是有上下文的,因此在保存的時候需要保存相關的信息,同時還有一些使用了函數之類的語句無法被記錄復制。
- row:不記錄sql語句上下文相關信息,僅保存哪條記錄被修改。記錄單元為每一行的改動,由于很多操作,會導致大量行的改動(比如alter table),因此這種模式的文件保存的信息太多,日志量太大。
- mixed:一種折中的方案,普通操作使用statement記錄,當無法使用statement的時候使用row。
undo log 是如何保證事務的原子性的?
通過使用 undo log,數據庫系統可以記錄事務過程中每次數據修改之前的舊值。當事務失敗或被中止時,數據庫可以利用這些記錄將數據恢復到事務開始之前的狀態,從而保證事務的原子性。
Undo log 的這種機制確保了即使在事務執行過程中出現錯誤,數據庫仍然能夠保持一致性和原子性。
慢查詢日志有什么用?
慢查詢日志用于捕捉和記錄執行時間超過指定閾值的 SQL 查詢。慢查詢日志在數據庫性能優化和問題診斷中發揮著重要作用。
事務的四大特性?
事務特性ACID:原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability)。
- 原子性(Atomicity):語句要么全執行,要么全不執行,是事務最核心的特性,事務本身就是以原子性來定義的;實現主要基于undo log
- 持久性(Durability):保證事務提交后不會因為宕機等原因導致數據丟失;實現主要基于redo log
- 隔離性(Isolation):數據庫允許多個并發事務同時對其數據進行讀寫和修改的能力,隔離性保證事務執行盡可能不受其他事務影響;InnoDB默認的隔離級別是RR,RR的實現主要基于鎖機制(包含next-key lock)、MVCC(包括數據的隱藏列、基于undo log的版本鏈、ReadView)
- 一致性(Consistency):事務追求的最終目標,是指事務操作前和操作后,數據滿足完整性約束,數據庫保持一致性狀態。一致性的實現既需要數據庫層面的保障,也需要應用層面的保障
常見的InnoDB是支持事務的,但是MyISAM是不支持事務的
詳情可以看這篇文章:MySQL事務原理:從ACID到隔離級別的全解析
數據庫的三大范式
第一范式1NF
確保數據庫表字段的原子性。
比如字段 userInfo: 廣東省 10086' ,依照第一范式必須拆分成 userInfo: 廣東省 userTel: 10086兩個字段。
第二范式2NF
首先要滿足第一范式,另外包含兩部分內容,一是表必須有一個主鍵;二是非主鍵列必須完全依賴于主鍵,而不能只依賴于主鍵的一部分。
舉個例子。假定選課關系表為student_course(student_no, student_name, age, course_name, grade, credit),主鍵為(student_no, course_name)。其中學分完全依賴于課程名稱,姓名年齡完全依賴學號,不符合第二范式,會導致數據冗余(學生選n門課,姓名年齡有n條記錄)、插入異常(插入一門新課,因為沒有學號,無法保存新課記錄)等問題。
應該拆分成三個表:學生:student(stuent_no, student_name, 年齡);課程:course(course_name, credit);選課關系:student_course_relation(student_no, course_name, grade)。
第三范式3NF
首先要滿足第二范式,另外非主鍵列必須直接依賴于主鍵,不能存在傳遞依賴。即不能存在:非主鍵列 A 依賴于非主鍵列 B,非主鍵列 B 依賴于主鍵的情況。
假定學生關系表為Student(student_no, student_name, age, academy_id, academy_telephone),主鍵為"學號",其中學院id依賴于學號,而學院地點和學院電話依賴于學院id,存在傳遞依賴,不符合第三范式。
可以把學生關系表分為如下兩個表:學生:(student_no, student_name, age, academy_id);學院:(academy_id, academy_telephone)。
2NF和3NF的區別?
- 2NF依據是非主鍵列是否完全依賴于主鍵,還是依賴于主鍵的一部分。
- 3NF依據是非主鍵列是直接依賴于主鍵,還是直接依賴于非主鍵。
并發事務帶來了哪些問題?
先了解下幾個概念:臟讀、不可重復讀、幻讀。
- 臟讀是指在一個事務處理過程里讀取了另一個未提交的事務中的數據。
- 不可重復讀是指在對于數據庫中的某行記錄,一個事務范圍內多次查詢卻返回了不同的數據值,這是由于在查詢間隔,另一個事務修改了數據并提交了。
- 幻讀是當某個事務在讀取某個范圍內的記錄時,另外一個事務又在該范圍內插入了新的記錄。對幻讀的正確理解是一個事務內的讀取操作的結論不能支撐之后業務的執行。假設事務要新增一條記錄,主鍵為id,在新增之前執行了select,沒有發現id為xxx的記錄,但插入時出現主鍵沖突,這就屬于幻讀,讀取不到記錄卻發現主鍵沖突是因為記錄實際上已經被其他的事務插入了,但當前事務不可見。
不可重復讀和幻讀有什么區別?
- 不可重復讀的重點是內容修改或者記錄減少比如多次讀取一條記錄發現其中某些記錄的值被修改;
- 幻讀的重點在于記錄新增比如多次執行同一條查詢語句(DQL)時,發現查到的記錄增加了。
幻讀其實可以看作是不可重復讀的一種特殊情況,單獨把幻讀區分出來的原因主要是解決幻讀和不可重復讀的方案不一樣。
事務隔離級別有哪些?
事務隔離就是為了解決上面提到的臟讀、不可重復讀、幻讀這幾個問題。
MySQL數據庫為我們提供的四種隔離級別:
- Serializable (串行化):通過強制事務排序,使之不可能相互沖突,從而解決幻讀問題。
- Repeatable read (可重復讀):MySQL的默認事務隔離級別,它確保同一事務的多個實例在并發讀取數據時,會看到同樣的數據行,解決了不可重復讀的問題。
- Read committed (讀已提交):一個事務只能看見已經提交事務所做的改變。可避免臟讀的發生。
- Read uncommitted (讀未提交):所有事務都可以看到其他未提交事務的執行結果。
生產環境數據庫一般用的什么隔離級別呢?
生產環境大多使用RC。為什么不是RR呢?
可重復讀(Repeatable Read),簡稱為RR
讀已提交(Read Commited),簡稱為RC
緣由一:在RR隔離級別下,存在間隙鎖,導致出現死鎖的幾率比RC大的多!
緣由二:在RR隔離級別下,條件列未命中索引會鎖表!而在RC隔離級別下,只鎖行!
也就是說,RC的并發性高于RR。
并且大部分場景下,不可重復讀問題是可以接受的。畢竟數據都已經提交了,讀出來本身就沒有太大問題!
并發事務的控制方式有哪些?
MySQL 中并發事務的控制方式無非就兩種:鎖 和 MVCC。鎖可以看作是悲觀控制的模式,多版本并發控制(MVCC,Multiversion concurrency control)可以看作是樂觀控制的模式。
鎖 控制方式下會通過鎖來顯式控制共享資源而不是通過調度手段,MySQL 中主要是通過 讀寫鎖 來實現并發控制。
- 共享鎖(S 鎖):又稱讀鎖,事務在讀取記錄的時候獲取共享鎖,允許多個事務同時獲?。ㄦi兼容)。
- 排他鎖(X 鎖):又稱寫鎖/獨占鎖,事務在修改記錄的時候獲取排他鎖,不允許多個事務同時獲取。如果一個記錄已經被加了排他鎖,那其他事務不能再對這條記錄加任何類型的鎖(鎖不兼容)。
讀寫鎖可以做到讀讀并行,但是無法做到寫讀、寫寫并行。另外,根據根據鎖粒度的不同,又被分為 表級鎖(table-level locking) 和 行級鎖(row-level locking) 。InnoDB 不光支持表級鎖,還支持行級鎖,默認為行級鎖。行級鎖的粒度更小,僅對相關的記錄上鎖即可(對一行或者多行記錄加鎖),所以對于并發寫入操作來說, InnoDB 的性能更高。不論是表級鎖還是行級鎖,都存在共享鎖(Share Lock,S 鎖)和排他鎖(Exclusive Lock,X 鎖)這兩類。
MVCC 是多版本并發控制方法,即對一份數據會存儲多個版本,通過事務的可見性來保證事務能看到自己應該看到的版本。通常會有一個全局的版本分配器來為每一行數據設置版本號,版本號是唯一的。
MVCC 在 MySQL 中實現所依賴的手段主要是: 隱藏字段、read view、undo log。
- undo log : undo log 用于記錄某行數據的多個版本的數據。
- read view 和 隱藏字段 : 用來判斷當前版本數據的可見性。
Mysql是如何實現事務的?
MySQL 主要是通過:鎖、RedoLog、Undo Log、MVCC 來實現事務:MySQL利用鎖(行鎖、間隙鎖等等)機制,使用數據并發修改的控制,滿足事務的隔離性
它會記錄事務對數據庫的所有修改,當 MSQL 發生宕機或崩潰時,通過重放redolog 就可以恢復數據,用來滿足事務的持久性。
Redo Log(重做日志),UndoLog(回滾日志),它會記錄事務的反向操作,簡單地說就是保存數據的歷史版本,用于事務的回滾,使得事務執行失敗之后可以恢復之前的樣子。實現原子性和隔離性
MVCC(多版本并發控制),滿足了非鎖定讀的需求,提高了并發度,實現了讀已提交和可重復讀兩種隔離級別,實現了事務的隔離性。
其實事務主要是為了實現一致性,具體是通過 AID,即原子性、隔離性和持久性來達到一致性的目的。
事務的二階段提交是什么?
MySQL事務的二階段提交是指在MySQL中,為了確保redo log(重做日志)和binlog(二進制日志)之間的一致性,使用的一種機制,MySQL 通過二階段提交來保證在crash recovery(崩潰恢復)時,不會出現數據丟失或數據不一致的情況。
二階段提交的兩個階段:
- 準備階段(Prepare phase):在事務提交時,MySQL 的InnoDB引擎會先寫入 redolog,并將其狀態標記為prepare,表示事務已經準備提交但還未真正完成,此時的 redo 1og是預提交狀態,還未標記為完成交。
- 提交階段(Commit phase): 當redo log 的狀態變為 pepare后,MySQLSener會寫入 binlog(記錄用戶的DML操作),binlog寫入成動后,MySQL 會通過 lnnoDB,將 redo log 狀態改為commit,完成整個事務的提交過程。
詳情可以看這篇文章:Mysql篇-三大日志
MySQL 的隔離級別是基于鎖實現的嗎?
MySQL 的隔離級別基于鎖和 MVCC 機制共同實現的。
SERIALIZABLE 隔離級別是通過鎖來實現的,READ-COMMITTED 和 REPEATABLE-READ 隔離級別是基于 MVCC 實現的。不過, SERIALIZABLE 之外的其他隔離級別可能也需要用到鎖機制,就比如 REPEATABLE-READ 在當前讀情況下需要使用加鎖讀來保證不會出現幻讀。
表級鎖和行級鎖了解嗎?有什么區別?
MyISAM 僅僅支持表級鎖(table-level locking),一鎖就鎖整張表,這在并發寫的情況下性非常差。InnoDB 不光支持表級鎖(table-level locking),還支持行級鎖(row-level locking),默認為行級鎖。
行級鎖的粒度更小,僅對相關的記錄上鎖即可(對一行或者多行記錄加鎖),所以對于并發寫入操作來說, InnoDB 的性能更高。
表級鎖和行級鎖對比:
- 表級鎖: MySQL 中鎖定粒度最大的一種鎖(全局鎖除外),是針對非索引字段加的鎖,對當前操作的整張表加鎖,實現簡單,資源消耗也比較少,加鎖快,不會出現死鎖。不過,觸發鎖沖突的概率最高,高并發下效率極低。表級鎖和存儲引擎無關,MyISAM 和 InnoDB 引擎都支持表級鎖。
- 行級鎖: MySQL 中鎖定粒度最小的一種鎖,是 針對索引字段加的鎖 ,只針對當前操作的行記錄進行加鎖。 行級鎖能大大減少數據庫操作的沖突。其加鎖粒度最小,并發度高,但加鎖的開銷也最大,加鎖慢,會出現死鎖。行級鎖和存儲引擎有關,是在存儲引擎層面實現的。
行級鎖鎖的到底是什么?行級鎖的使用有什么注意事項?
MySQL 的 InnoDB 存儲引擎實現的行級鎖,實際上鎖定的是基于索引的行記錄。這意味著,行鎖針對的是數據表中的索引記錄,而非數據表本身的物理行。
InnoDB 的行鎖是針對索引字段加的鎖,表級鎖是針對非索引字段加的鎖。當我們執行 UPDATE、DELETE 語句時,如果 WHERE條件中字段沒有命中唯一索引或者索引失效的話,就會導致掃描全表對表中的所有行記錄進行加鎖。這個在我們日常工作開發中經常會遇到,一定要多多注意?。?!
不過,很多時候即使用了索引也有可能會走全表掃描,這是因為 MySQL 優化器的原因。
InnoDB 有哪幾類行鎖?
InnoDB 行鎖是通過對索引數據頁上的記錄加鎖實現的,MySQL InnoDB 支持三種行鎖定方式:
- 記錄鎖(Record Lock):也被稱為記錄鎖,屬于單個行記錄上的鎖。
- 間隙鎖(Gap Lock):鎖定一個范圍,不包括記錄本身。
- 臨鍵鎖(Next-Key Lock):Record Lock+Gap Lock,鎖定一個范圍,包含記錄本身,主要目的是為了解決幻讀問題(MySQL 事務部分提到過)。記錄鎖只能鎖住已經存在的記錄,為了避免插入新記錄,需要依賴間隙鎖。
在 InnoDB 默認的隔離級別 REPEATABLE-READ 下,行鎖默認使用的是 Next-Key Lock。但是,如果操作的索引是唯一索引或主鍵,InnoDB 會對 Next-Key Lock 進行優化,將其降級為 Record Lock,即僅鎖住索引本身,而不是范圍。
一些大廠面試中可能會問到 Next-Key Lock 的加鎖范圍,詳細可以查看:行級鎖怎么加的? 。
共享鎖和排他鎖
SELECT 的讀取鎖定主要分為兩種方式:共享鎖和排他鎖。
select * from table where id<6 lock in share mode;--共享鎖
select * from table where id<6 for update;--排他鎖
這兩種方式主要的不同在于LOCK IN SHARE MODE 多個事務同時更新同一個表單時很容易造成死鎖。
申請排他鎖的前提是,沒有線程對該結果集的任何行數據使用排它鎖或者共享鎖,否則申請會受到阻塞。在進行事務操作時,MySQL會對查詢結果集的每行數據添加排它鎖,其他線程對這些數據的更改或刪除操作會被阻塞(只能讀操作),直到該語句的事務被commit語句或rollback語句結束為止。
SELECT... FOR UPDATE 使用注意事項:
for update僅適用于innodb,且必須在事務范圍內才能生效。- 根據主鍵進行查詢,查詢條件為
like或者不等于,主鍵字段產生表鎖。 - 根據非索引字段進行查詢,會產生表鎖。
MVCC 實現原理?
詳細請查看:ReadView
MVCC(Multiversion concurrency control) 就是同一份數據保留多版本的一種方式,進而實現并發控制。在查詢的時候,通過read view和版本鏈找到對應版本的數據。
作用:提升并發性能。對于高并發場景,MVCC比行級鎖開銷更小。
MVCC 實現原理如下:
- 首先獲取事務自己的事務 ID;
- 獲取 ReadView;
- 查詢得到的數據,然后與 ReadView 中的事務版本號(m_ids,min_trx_id,max_trx_id)進行比較;
- 如果不符合 ReadView 規則,就需要從 Undo Log 中(即根據roll_point)獲取歷史快照;
- 最后返回符合規則的數據。 在隔離級別為讀已提交(Read Committed)時,一個事務中的每一次 SELECT 查詢都會重新獲取一次Read View
Read View的規則
- 如果記錄的 trx_id 值小于 Read View 中的 min_trx_id 值,表示這個版本的記錄是在創建 Read View 前 已經提交的事務生成的,所以該版本的記錄對當前事務可見。
- 如果記錄的 trx_id 值大于等于 Read View 中的 max_trx_id 值,表示這個版本的記錄是在創建 Read View 后 才啟動的事務生成的,所以該版本的記錄對當前事務不可見。
- 如果記錄的 trx_id 值在 Read View 的 min_trx_id 和 max_trx_id 之間,需要判斷 trx_id 是否在 m_ids 列表中:
- 如果記錄的 trx_id 在 m_ids 列表中,表示生成該版本記錄的活躍事務依然活躍著(還沒提交事務),所以該版本的記錄對當前事務不可見。
- 如果記錄的 trx_id 不在 m_ids列表中,表示生成該版本記錄的活躍事務已經被提交,所以該版本的記錄對當前事務可見。
如果 MySQL中沒有 MVCC,會有什么影響?
如果沒有 MVCC,系統必須頻繁地對讀寫操作進行加鎖來保證數據的正確性,因為增加了鎖的獲取和釋放的開銷,會導致整體系統響應速度變慢,這種實現叫 LBCC (Lock-Based Concurrent Control).
快照讀和當前讀
表記錄有兩種讀取方式。
-
快照讀:讀取的是快照版本。普通的
SELECT就是快照讀。通過mvcc來進行并發控制的,不用加鎖。 -
當前讀:讀取的是最新版本。
UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE是當前讀。
快照讀情況下,InnoDB通過mvcc機制避免了幻讀現象。而mvcc機制無法避免當前讀情況下出現的幻讀現象。因為當前讀每次讀取的都是最新數據,這時如果兩次查詢中間有其它事務插入數據,就會產生幻讀。
select...for update會鎖表還是鎖行?
如果查詢條件用了索引/主鍵,那么select ... for update就會加行鎖。
如果是普通字段(沒有索引/主鍵),那么select ..... for update就會加表鎖。
update 是鎖行還是鎖表?
首先,InnoDB行鎖是通過給索引上的索引項加鎖來實現的,只有通過索引條件檢索數據,InnoDB才使用行級鎖,否則,InnoDB將使用表鎖。
- 當執行update語句時,where中的過濾條件列,如果用到索引,就是鎖行;如果無法用索引,就是鎖表。
- 如果兩個update語句同時執行,第一個先執行觸發行鎖,但是第二個沒有索引觸發表鎖,因為有個行鎖住了,所以還是會等待行鎖釋放,才能鎖表。
- 當執行insert或者delete語句時,鎖行。
MySQL是如何避免幻讀的?
- 在快照讀情況下,MySQL通過
mvcc來避免幻讀。 - 在當前讀情況下,MySQL通過
next-key來避免幻讀(加行鎖和間隙鎖來實現的)。
next-key包括兩部分:行鎖和間隙鎖。行鎖是加在索引上的鎖,間隙鎖是加在索引之間的。
Serializable隔離級別也可以避免幻讀,會鎖住整張表,并發性極低,一般不會使用。
樂觀鎖和悲觀鎖是什么?
數據庫中的并發控制是確保在多個事務同時存取數據庫中同一數據時不破壞事務的隔離性和統一性以及數據庫的統一性。樂觀鎖和悲觀鎖是并發控制主要采用的技術手段。
- 悲觀鎖:假定會發生并發沖突,會對操作的數據進行加鎖,直到提交事務,才會釋放鎖,其他事務才能進行修改。實現方式:使用數據庫中的鎖機制。
- 樂觀鎖:假設不會發生并發沖突,只在提交操作時檢查是否數據是否被修改過。給表增加
version字段,在修改提交之前檢查version與原來取到的version值是否相等,若相等,表示數據沒有被修改,可以更新,否則,數據為臟數據,不能更新。實現方式:樂觀鎖一般使用版本號機制或CAS算法實現。
MySQL只操作同一條記錄也會死鎖嗎
在MySQL中,即使多個事務僅對同一條記錄進行操作,也可能發生死鎖。這通常與InnoDB存儲引擎的鎖管理機制有關。以下是一些觸發這種情況的場景:
索引導致的鎖競爭:如果事務在WHERE子句中使用不同的索引來查找相同的行,InnoDB可能會導致多個事務以不同順序鎖住這些索引,從而產生死鎖。
自增鎖(auto-increment lock):在使用自增列時,不同事務可能在等待獲取表級鎖來增加自增值,某些情況下也會出現死鎖。
外鍵約束:外鍵檢查過程中可能會涉及多個表,多個事務可能會因為不同的鎖順序而陷入死鎖。
MySQL 中如果發生死鎖應該如何解決?
自動檢測與回滾:MySQL自帶死鎖檢測機制(innodb deadlock detect),當檢測到死鎖時,數據庫會自動回滾其中一個事務,以解除死鎖。通常會回滾事務中持有最少資源的那個。也有鎖等待超時的參數(innodblock wait timeout),當獲取鎖的等待時間超過閾值時,就釋放鎖進行回滾
手動 kill 發生死鎖的語句:可以通過命令,手動快速地找出被阻塞的事務及其線程ID,然后手動 kill它,及時釋放資源
MySQL 中長事務可能會導致哪些問題?
- 長時間的鎖競爭,阻塞資源:長事務持有鎖的時間較長,容易導致其他事務在嘗試獲取相同鎖時發生阻塞,從而增加系統的等待時間和降低并發性能。業務線程也會因為長時間的數據庫請求等待而阻塞,部分業務的阻塞可能還會影響到別的服務,導致產生雪崩,最終使得服務全面崩盤,導致非常嚴重的線上事故。
- 死鎖風險:長事務更容易產生死鎖,因為多個事務可能在互相等待對方釋放鎖,導致系統無法繼續執行。
- 主從延遲:主庫需要長時間執行,然后傳輸給從庫,從庫又要重放好久,期間可能有很長一段時間數據是不同步的。
- 回滾導致時間浪費:如果長事務執行很長一段時間,中間突發狀況導致拋錯,使得事務回滾了,之前做的執行都浪費了。
本文來自在線網站:seven的菜鳥成長之路,作者:seven,轉載請注明原文鏈接:www.seven97.top

浙公網安備 33010602011771號