數(shù)據(jù)庫原理-01
事務(wù):
指的是數(shù)據(jù)庫滿足ACID特性的一組操作,這組操作要么不做,要么全做
事務(wù)是恢復(fù)和并發(fā)控制的基本單位
ACID
A: Atomicity 原子性
事務(wù)可以看作是不可分割的最小單元,事務(wù)的操作要么都成功,要么都失敗回滾
C: Consistency 一致性
事務(wù)在執(zhí)行前后都要保持一致性狀態(tài),比如結(jié)算訂單操作
I: Isolation 隔離性
一個事務(wù)在未提交之前的操作,不能被其他事物影響
D: Durability 持久性
一旦事務(wù)提交,其所做的修改將會永久保存到數(shù)據(jù)庫當(dāng)中,即使系統(tǒng)崩潰,事務(wù)執(zhí)行的結(jié)果也不會丟失
回滾實現(xiàn):
回滾日志(Undo Log)實現(xiàn),回滾日志記錄事務(wù)執(zhí)行的修改操作,在回滾時反向執(zhí)行這些修改操作
系統(tǒng)崩潰修復(fù):
重做日志(Redo Log)進行恢復(fù),從而實現(xiàn)持久性,與回滾日志記錄數(shù)據(jù)的邏輯修改不同,重做日志記錄的數(shù)據(jù)頁的物理修改
MYSQL默認采用自動提交模式 AUTOCOMMIT
并發(fā)一致性問題
并發(fā)環(huán)境下,事物的隔離性很難保證,因此會出現(xiàn)并發(fā)一致性問題
丟失修改
t1 write A = 10
t2 write A = 20
t2覆蓋t1的修改
臟讀
t1 read A = 10
t1 write A = 20
t2 read A = 20
t1 rollback then A = 10?
t2出現(xiàn)讀的數(shù)據(jù)不是回滾后的數(shù)據(jù)
不可重復(fù)讀
t2 read A = 10
t1 write A = 20
t2 read A = 20
t2 第一次和第二次讀取的結(jié)果不一致
幻讀
t1 read size1 = select count(*)?
t2 insert ....
t1 read size2 = select count(*)
t1 第一次和第二次讀的操作不一致
并發(fā)不一致的原因:破壞了事務(wù)的隔離性
解決方法:通過并發(fā)機制保證隔離性,有封鎖和DBMS提供的事務(wù)隔離級別
封鎖:
鎖的粒度:
行級鎖:INnoDB
表級鎖:MyISAM
鎖的開銷以及并發(fā)程度是選擇哪種鎖的標(biāo)準
鎖類型:
讀寫鎖
互斥鎖:寫鎖
A加寫鎖后,可以對A進行read,update操作,期間其他事務(wù)不能對A加鎖
共享鎖:讀鎖
A加讀鎖后,可以對A進行read,不能進行update操作,加鎖期間,其他事務(wù)可以對A加讀鎖,不能加寫鎖
X S
X - -
S? ?-? ?
意向鎖
IX,IS
IX/IS,IX/IS 都是表鎖
一個事務(wù)在獲得某個數(shù)據(jù)行對象的 S 鎖之前,必須先獲得表的 IS 鎖或者更強的鎖;
一個事務(wù)在獲得某個數(shù)據(jù)行對象的 X 鎖之前,必須先獲得表的 IX 鎖。
封鎖協(xié)議
三級封鎖協(xié)議
1:事務(wù) T 要修改數(shù)據(jù) A 時必須加 X 鎖,直到 T 結(jié)束才釋放鎖。
2:在一級的基礎(chǔ)上,要求讀取數(shù)據(jù) A 時必須加 S 鎖,讀取完馬上釋放 S 鎖。
3:在二級的基礎(chǔ)上,要求讀取數(shù)據(jù) A 時必須加 S 鎖,直到事務(wù)結(jié)束了才能釋放 S 鎖。
隔離級別
Read Uncommitted 讀未提交 啥都解決不了
Read committed? ?讀已提交 解決臟讀
Repeatable read 可重復(fù)讀 保證在同一事務(wù)中多次讀取同一數(shù)據(jù)的結(jié)果是一樣的,解決不了幻讀
Serializable 可串行化 強制事務(wù)串行執(zhí)行:四種并發(fā)一執(zhí)行都可避免
MVCC Multi Version Concurrency Control 多版本并發(fā)控制
MYSQL的InnoDB存儲引擎實現(xiàn)隔離級別的一種具體方式,用于實現(xiàn)read committed和repeatable read兩種隔離級別。
read uncommitted總是讀取最新的數(shù)據(jù)行,要求很低,無需使用MVCC。
Serializable 需要使用對所有讀取的行都加鎖,單純使用MVCC無法實現(xiàn)
基本思想:
加鎖能解決多個事務(wù)同時執(zhí)行出現(xiàn)的并發(fā)一致性問題
實際場景:read is more than write,因此引入讀寫鎖來避免不必要的加鎖操作。
例如read and write沒有互斥關(guān)系,讀寫鎖中讀和寫仍然是互斥的。
MVCC利用多版本的思想,寫操作更新最新的快照版本,讀操作去讀舊版本快照,沒有互斥關(guān)系
CopyOnWrite類似
CopyOnWriteArrayList?
在寫的過程通過復(fù)制,更新引用來實現(xiàn)消除避免讀寫鎖的使用,適合讀多寫少的場景,也就是讀寫分離的代表
MVCC事務(wù)的修改:delete insert update會為數(shù)據(jù)行新增一個版本快照
臟讀和不可重復(fù)讀最根本的原因:事務(wù)讀取到其他事務(wù)未提交的修改
MVCC規(guī)定只能讀取已經(jīng)提交的快照。
一個事務(wù)可以讀取自身的未提交的快照,這不算是臟讀
版本號
SYS_ID:是一個遞增的數(shù)字,每開始一個新的事務(wù),系統(tǒng)版本號就會自動遞增
TRX_ID:事務(wù)開始時的系統(tǒng)版本號
Uudo日志
MVCC的多版本指的是多個版本的快照,快照存儲在Undo日志中,該日志通過回滾指針Roll_ptr把一個數(shù)據(jù)行的所有快照連接起來
快照:類似于鏈表的節(jié)點,DEL一個bit,標(biāo)識是否被刪除
insert,update,delete操作會創(chuàng)建一個日志,并將事務(wù)版本號TRX_ID寫入
ReadView
MVCC維護了一個ReadView結(jié)構(gòu),保存當(dāng)前系統(tǒng)未提交的事務(wù)列表
trx_ids = {trx_id1,trx_id2....},還有該列表的最小值trx_id_min,trx_id_max
快照讀and當(dāng)前讀
快照讀:select,不需要進行加鎖操作
當(dāng)前讀:insert,update,delete 需要進行加鎖,從而讀取最新的數(shù)據(jù)
在進行select操作,可以強制進行加鎖操作
select * from table where ? lock in share mode.? ?add 讀鎖
select * from table where ? for update.? ?add 寫鎖
Next-Key Locks?
是 MySQL的InnoDB存儲引擎的一種鎖實現(xiàn)。
InnoDB 使用 MVCC + Next-Key Locks 可以解決幻讀問題
Record Locks
鎖定一個記錄上的索引,而不是記錄本身。
Gap Locks
鎖定索引之間的間隙,但是不包含索引本身
SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
Next-Key Locks?
它是 Record Locks 和 Gap Locks 的結(jié)合,不僅鎖定一個記錄上的索引,也鎖定索引之間的間隙。
三大范式
第一范式:保證每列的原子性,即列不可分
第二范式:第一范式基礎(chǔ)上,非主屬性完全函數(shù)依賴于主鍵。即消除部份函數(shù)依賴
第三范式:第二范式基礎(chǔ)上,非主屬性不傳遞函數(shù)依賴于主鍵,即消除傳遞依賴