濟南營銷型網(wǎng)站建設(shè)百度推廣400電話
一、事務(wù)
數(shù)據(jù)庫事務(wù)的特性?
數(shù)據(jù)庫事務(wù)的四大特性是ACID。
- 原子性:就是所有操作要么全不做,要不全做。通過undo日志來實現(xiàn)。
- 一致性:就是在并發(fā)情況下數(shù)據(jù)庫由一個狀態(tài)轉(zhuǎn)移到另一個狀態(tài)的數(shù)據(jù)要一致。通過事務(wù)的隔離級別來實現(xiàn)。
- 隔離性:多個事務(wù)的操作互相不影響,數(shù)據(jù)有4種隔離級別來解決?;阪i+mvcc機制來實現(xiàn)。
- 持久性:數(shù)據(jù)庫中事務(wù)一旦提交,數(shù)據(jù)持久到硬盤中。基于redo日志來實現(xiàn)。
數(shù)據(jù)不一致的問題
- 臟讀:事務(wù)A讀取一個數(shù)據(jù),事務(wù)B對該數(shù)據(jù)進行修改,修改前后的數(shù)據(jù)都可以讀到,但是數(shù)據(jù)會不一樣,導(dǎo)致了臟讀。臟讀強調(diào)的是讀到其他事務(wù)未提交的數(shù)據(jù)。
- 不可重復(fù)讀:事務(wù)A讀一個數(shù)據(jù),事務(wù)B對該數(shù)據(jù)進行修改后提交,導(dǎo)致事務(wù)A前后讀取的數(shù)據(jù)值不一致。不可重復(fù)度強調(diào)的是讀到其他事務(wù)提交后的數(shù)據(jù)和提交前的數(shù)據(jù)不一致。
- 幻讀:事務(wù)A讀取一個數(shù)據(jù),事務(wù)B在insert、delete增刪記錄,事務(wù)A兩次讀取的數(shù)據(jù)條數(shù)不一致;
事務(wù)的隔離級別
事務(wù)的隔離級別描述的是在多個事務(wù)同時運行過程中各自事務(wù)中數(shù)據(jù)的隔離辦法,事務(wù)的隔離級別是為了解決數(shù)據(jù)庫中以上常見的三類問題,包括:臟讀、不可重復(fù)讀和幻讀的問題,者四類隔離級別分別為:
- 未提交讀:事務(wù)A可以讀到事務(wù)B未提交的數(shù)據(jù);
- 已提交讀:事務(wù)A只能讀到事務(wù)B提交后的數(shù)據(jù);
- 可重復(fù)讀:事務(wù)A能讀取到事務(wù)B還未執(zhí)行完的數(shù)據(jù),但是讀取到的是事務(wù)B未開始事務(wù)前的數(shù)據(jù),只有當事務(wù)B執(zhí)行完成了才會讀取到新的數(shù)據(jù);
- 可串形化:事務(wù)A、事務(wù)B的讀寫操作是串形化的;
總結(jié):
- 以上4類隔離級別的約束條件從寬松到嚴格;
- 未提交讀隔離級別沒有解決任何問題;
- 已提交讀解決了臟讀的問題;
- 可重復(fù)讀解決了不可重復(fù)讀的問題,但還存在幻讀的問題,但結(jié)合MVCC和record lock能解決幻讀的問題;
- 只有可串形化隔離級別能解決所有數(shù)據(jù)不一致的問題;
- Mysql的默認隔離級別是可重復(fù)讀。
mysql如何解決幻讀?
在快照讀情況下,即不加鎖的非阻塞讀,像普通select操作下通過mvcc避免幻讀;通過樂觀鎖類避免。
對于可重復(fù)讀的隔離級別下,select * from table的語句是采用快照讀的模式,新的事務(wù)會讀快照;
在當前讀情況下,當前讀表示需要讀取當前最新數(shù)據(jù),是加鎖的阻塞讀寫操作,像普通update/insert/delete和加update的select操作,是通過next-key lock避免幻讀;通過悲觀鎖來避免。
對于可重復(fù)讀的隔離級別,如果是當前讀場景,需要通過間隙鎖(Gap Lock)模式來避免幻讀,這樣行間間距會被加鎖,不會被新的事務(wù)插入新的數(shù)據(jù),間隙鎖加行鎖合起來稱為next-key lock;
二、鎖
鎖是計算機中協(xié)調(diào)多線程并發(fā)訪問共享資源的機制,在數(shù)據(jù)庫中就是協(xié)調(diào)多個事務(wù)同時訪問同一數(shù)據(jù)記錄的機制,在Mysql數(shù)據(jù)庫中進行加鎖的對象是索引中的索引項,會在索引項上做加鎖標記。
鎖的分類
mysql數(shù)據(jù)庫的鎖分為行鎖和表鎖。
行鎖。是innodb存儲引擎的默認加鎖方式,特點是開銷大,加鎖慢,鎖力度小,所以并發(fā)度高,適合寫多讀少場景。
表鎖。是myisam存儲引擎的默認加鎖方式,特點是開銷小,加鎖快,鎖粒度大,所以并發(fā)度低,適合讀多寫少場景。
記錄鎖(Record lock):即是行級鎖,是innodb存儲引擎的默認加鎖方式。
間隙鎖(Gap lock):會對記錄之間的左開右閉的區(qū)間進行加鎖;
臨鍵鎖(Next key Lock):記錄鎖+間隙鎖統(tǒng)稱為臨鍵鎖。
共享鎖(讀鎖)&獨占鎖(寫鎖):共享鎖又稱S鎖/讀鎖,對記錄進行讀操作時進行加的鎖,可以共享;獨占鎖又稱X鎖/寫鎖,對記錄進行寫操作時進行加鎖,只能獨占;
意向共享鎖&意向排它鎖:為了解決對記錄加了共享鎖&獨占鎖,再對表加表鎖的時候需要遍歷,所以在對行加共享鎖&獨占鎖時候,會對表加上意向共享鎖&意向排它鎖,下次加表鎖一目了然,這是一類表鎖。
插入意向鎖:就是多個事務(wù)在進行插入的時候,已經(jīng)有事務(wù)在進行插入操作了,另一個在等待的事務(wù)需要加上插入意向鎖,用以表面針對目前的間隙位置有插入的需求;
數(shù)據(jù)庫里的樂觀鎖和悲觀鎖?
所有需要加鎖的操作都是在進行多線程情況下才需要的。
- 樂觀鎖比較好理解,就是預(yù)測所有線程對數(shù)據(jù)的操作都是不會沖突的,所以每次對數(shù)據(jù)進行操作時候都不會加上鎖;mysql內(nèi)部機制可以通過mvcc機制來是實現(xiàn)樂觀鎖;
- 悲觀鎖則相反,就是認為每次線程對數(shù)據(jù)的操作都可能存在沖突,所以需要對數(shù)據(jù)加上行鎖、表鎖等。mysql主要通過record lock+nextKey lock來實現(xiàn)。
mysql的悲觀鎖實現(xiàn)?
mysql加鎖是通過鎖住索引來實現(xiàn)的,如果沒有索引和主鍵則會鎖住整張表。mysql是通過record lock、Gap lock和next-key lock來實現(xiàn)加鎖策略的。
- Record lock:對行進行加鎖
- Gap lock:對間隙進行加鎖
- Next-key lock:Record lock+Gap lock的統(tǒng)稱,innodb的默認實現(xiàn)方案;
InnoDB在執(zhí)行查詢語句SELECT時(非串行隔離級別),不會加鎖。但是update、insert、delete操作會加行 鎖。
mysql默認是autocommit提交事務(wù),如果需要對select語句加鎖,需要使用手動設(shè)置加鎖操作。手動設(shè)置加鎖的步驟:
begin;
Select * from xxx where xxx for update//加上for update進行強制加寫鎖;
select * from xxx where xxx lock in share mode//加上lock in share mode進行強制加讀鎖
進行各種操作//這樣的話在還么有commit之前,該行記錄一直處于鎖定狀態(tài);
commit;
mysql的樂觀鎖mvcc機制原理?
mysql是通過mvcc機制來實現(xiàn)樂觀鎖的。mvcc是一種不加鎖的方式解決讀寫沖突的機制,支持mysql上了寫鎖,還能繼續(xù)支持讀,解決讀操作阻塞寫操作的問題。在mysql中對一行記錄的讀寫,默認使用的是mvcc機制,避免頻繁使用加鎖機制影響性能。
主要通過隱含字段、undo日志和read view來實現(xiàn)。核心思想是在select查詢操作前生成一個read view(一致性讀視圖)中事務(wù)id的大小,用來判斷是否需要從undo日志組成的版本鏈中讀取歷史數(shù)據(jù)。
- 隱藏字段:每一條記錄都會隱藏row_id、trx_id、roll_ptr。
- undo日志:mysql中的undo日志記錄操作前的狀態(tài),可以實現(xiàn)回滾到之前狀態(tài)。
- read view:mysql中存在當前讀和快照讀的概念,mvcc是通過快照讀來實現(xiàn)多線程并發(fā)操作的,每次進行讀操作時,會生成一個read view,讀取之后比較事務(wù)id的大小來判斷是否進行了一致性讀。
mysql本身如何處理死鎖問題?
Mysql目前機制是死鎖超時會退出,將持有最少行級互斥鎖的事務(wù)回滾。針對mysql無法自己解決的死鎖問題,需要通過線程日志找到發(fā)生死鎖的線程id,再通過kill 殺掉發(fā)生死鎖的線程。
如何避免死鎖?
問題說明:
兩個或多個事務(wù)占用同一個共享資源,并且互相請求對方資源的鎖,這樣就會造成死鎖。比如事務(wù)A請求事務(wù)B加鎖的數(shù)據(jù),同時事務(wù)B請求事務(wù)A加鎖的數(shù)據(jù),這樣就會形成死鎖情況。
解決方案:
- 讓數(shù)據(jù)的查詢盡量索引完成,避免索引加鎖失敗,從行級鎖升級成表鎖。
- 保持事務(wù)的順序執(zhí)行;
- 盡量減少查詢范圍,避免間隙鎖加鎖的范圍;
- 事務(wù)執(zhí)行邏輯簡短,減少加鎖時間;
- 死鎖檢測。執(zhí)行之前做循環(huán)引用的檢測。
Mysql只操作一條記錄也有可能發(fā)生死鎖嗎?
有可能。Mysql的加鎖對象是索引而不是記錄,所以當一個事務(wù)對該記錄的非主鍵索引加鎖,并請求主鍵索引的鎖,但另一個事務(wù)對該記錄的主鍵索引已加鎖,并請求該記錄的非主鍵索引的鎖,那么就會進入死鎖狀態(tài)。
如何優(yōu)化事務(wù)
- 將數(shù)據(jù)處理工作放在事務(wù)外進行,縮短在事務(wù)中執(zhí)行的時間;
- 不要一次性創(chuàng)建邏輯流程太長的事務(wù),將這些事務(wù)拆分成多個小事務(wù);
- 事務(wù)中不要進行RPC等耗時較長的操作,調(diào)用超時可能導(dǎo)致事務(wù)超時;
本文由博客一文多發(fā)平臺 OpenWrite 發(fā)布!