資料庫事物 隔離等級及資料庫鎖機制

2022-08-19 11:48:09 字數 4166 閱讀 7155

事務(transaction)是資料庫管理系統的執行單位,可以是乙個資料庫操作(如select操作)或者是一組操作序列。事務acid屬性,即原子性(atomicity)、一致性(consistency)、隔離性(isolation)、永續性(durability)。

原子性(atomic):保證事務中的所有操作全部執行或全部不執行。例如執行轉賬事務,要麼轉賬成功,要麼失敗。成功,則金額從轉出帳戶轉入到目的帳戶,並且兩個帳戶金額將發生相應的變化;失敗,則兩個賬戶的金額都不變。不會出現轉出帳戶扣了錢,而目的帳戶沒有收到錢的情況。

一致性(consistency):保證資料庫始終保持資料的一致性——事務操作之前是一致的,事務操作之後也是一致的,不管事務成功與否。如上面的例子,轉賬之前和之後資料庫都保持資料上的一致性。

隔離性(isolation):多個事務併發執行的話,結果應該與多個事務序列執行效果是一樣的。顯然最簡單的隔離就是將所有事務都序列執行:先來先執行,乙個事務執行完了才允許執行下乙個。但這樣資料庫的效率低下,如:兩個不同的事務只是讀取同一批資料,這樣完全可以併發進行。為了控制併發執行的效果就有了不同的隔離級別。下面將詳細介紹。

永續性(durability):永續性表示事物操作完成之後,對資料庫的影響是持久的,即使資料庫因故障而受到破壞,資料庫也應該能夠恢復。通常的實現方式是採用日誌。

事務隔離級別(transaction isolation levels):隔離級別就是對對事務併發控制的等級。ansi/ iso

sql將其分為序列化(serializable)、可重複讀(repeatable read)、讀已提交(read commited)、讀未提交(read uncommited)四個等級。為了實現隔離級別通常資料庫採用鎖(lock)。一般在程式設計的時候只需要設定隔離等級,至於具體採用什麼鎖則由資料庫來設定。首先介紹四種等級,然後舉例解釋後面三個等級(可重複讀、讀已提交、讀未提交)中會出現的併發問題。

序列化(serializable):所有事務都乙個接乙個地序列執行,這樣可以避免幻讀(phantom reads)。對於基於鎖來實現併發控制的資料庫來說,序列化要求在執行範圍查詢(如選取年齡在10到30之間的使用者)的時候,需要獲取範圍鎖(range lock)。如果不是基於鎖實現併發控制的資料庫,則檢查到有違反序列操作的事務時,需要滾回該事務。

可重複讀(repeatable read):所有被select獲取的資料都不能被修改,這樣就可以避免乙個事務前後讀取資料不一致的情況。但是卻沒有辦法控制幻讀,因為這個時候其他事務不能更改所選的資料,但是可以增加資料,因為前乙個事務沒有範圍鎖。

讀已提交(read commited):被讀取的資料可以被其他事務修改。這樣就可能導致不可重複讀。也就是說,事務的讀取資料的時候獲取讀鎖,但是讀完之後立即釋放(不需要等到事務結束),而寫鎖則是事務提交之後才釋放。釋放讀鎖之後,就可能被其他事物修改資料。該等級也是sql server預設的隔離等級。

讀未提交(read uncommited):這是最低的隔離等級,允許其他事務看到沒有提交的資料。這種等級會導致髒讀(dirty read)。

例子:下面考察後面三種隔離等級對應的併發問題。假設有兩個事務。事務1執行查詢1,然後事務2執行查詢2,然後提交,接下來事務1中的查詢1再執行一次。查詢基於以下表進行:

users

id

name

age

1joe202

jill

25乙個事務中先後各執行一次同乙個查詢,但是返回的結果集卻不一樣。發生這種情況是因為在執行select操作的時候沒有獲取範圍鎖(range lock),導致其他事務仍然可以插入新的資料。

transaction 1

transaction 2

/* query 1 */
select * from users
where age between 10 and 30;

/* query 2 */
insert into users values ( 3, 'bob', 27 );
commit;

/* query 1 */
select * from users
where age between 10 and 30;

注意transaction 1對同乙個查詢語句(query 1)執行了兩次。 如果採用更高階別的隔離等級(即序列化)的話,那麼前後兩次查詢應該返回同樣的結果集。但是在可重複讀隔離等級中卻前後兩次結果集不一樣。但是為什麼叫做可重複讀等級呢?那是因為該等級解決了下面的不可重複讀問題。

在採用鎖來實現併發控制的資料庫系統中,不可重複讀是因為在執行select操作的時候沒有加讀鎖(read lock)。

transaction 1

transaction 2

/* query 1 */
select * from users where id = 1;

/* query 2 */
update users set age = 21 where id = 1;
commit;

/* query 1 */
select * from users where id = 1;

在這個例子當中,transaction 2提交成功,所以transaction 1第二次將獲取乙個不同的age 值.在serializable和repeatable read隔離級別中,資料庫應該返回同乙個值。而在read committed和read uncommitted級別中資料庫返回更新的值。這樣就出現了不可重複讀。

如果乙個事務2讀取了另乙個事務1修改的值,但是最後事務1滾回了,那麼事務2就讀取了乙個髒資料,這也就是所謂的髒讀。發生這種情況就是允許事務讀取未提交的更新。

transaction 1

transaction 2

/* query 1 */
select * from users where id = 1;

/* query 2 */
update users set age = 21 where id = 1;

/* query 1 */
select * from users where id = 1;

rollback

綜上述,可以等到下面的**:

隔離等級

髒讀不可重複讀

幻讀讀未提交

yesyes

yes讀已提交

noyes

yes可重複讀

nono

yes序列化

nono

no資料庫系統本身的鎖機制

1、共享鎖(shared lock)   select這種

2、更新鎖(update lock)   update 這種

3、排他鎖(exclusive lock):update set xx=c where id="3" 這種

4、意向鎖(intent lock):對錶進行加鎖。

5、模式鎖(schema lock):altert table

6、批量更新鎖(bulk update lock):資料庫備份恢復

業務級別上的鎖機制,如hibernated的鎖機制:

悲觀鎖:利用資料庫本身的鎖機制實現。通過上面對資料庫鎖的了解,可以根據具體業務情況綜合使用事務隔離級別與合理的手工指定鎖的方式比如降低鎖的粒度等減少併發等待。

樂觀鎖:利用程式處理併發。原理都比較好理解,基本一看即懂。方式大概有以下3種

對記錄加版本號.

對記錄加時間戳.

對將要更新的資料進行提前讀取、事後對比。

不論是資料庫系統本身的鎖機制,還是樂觀鎖這種業務資料級別上的鎖機制,本質上都是對狀態位的讀、寫、判斷。

參考:

資料庫(1)事物和事物的隔離等級

這一段時間一直在學習關係型資料庫,準備寫乙個小專題來總結一下這一段時間的學習結果。原子性 atomatic 資料庫事物包含的操作需要全部成功,否則進行回滾操作。一致性 consistency 資料得操作前後要保持一致,不會出現預期之外的改變。隔離性 isolation 隔離性是只多個使用者併發訪問同...

資料庫事物隔離級別

資料庫事物的隔離級別有4個,由低到高依次為 1.read uncommitted 兩個併發的事務,事務b讀取了事物a尚未提交的資料,出現髒讀。2.read committed 事務a事先讀取了資料,事務b緊接更新了資料,並提交了事務,而事務a再次讀取該資料時,資料已發生了改變,即所說的不可重複讀。3...

資料庫事物隔離級別

事物隔離級別 1 序列化 serializable 單位時間,只有乙個事物,強制事物排序,並行度低,效能差 2 可重複讀 repeatable read 讀操作可以並行,同乙個事物裡,所有讀操作的結果都是事物開始時的狀態 一致性 但可以增加新的記錄,mysql 預設事物隔離級別 3 讀已提交 rea...