事務(transaction)是資料庫管理系統的執行單位,可以是乙個資料庫操作(如select操作)或者是一組操作序列。事務acid屬性,即原子性(atomicity)、一致性(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
joejill
乙個事務中先後各執行一次同乙個查詢,但是返回的結果集卻不一樣。發生這種情況是因為在執行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參考:
isolation (database systems):
資料庫事務的隔離等級
資料庫的事務隔離級別有4個,由低到高依次是read uncommitted,read committed,repeatable read,serializable,這四個級別可以逐個解決髒讀,不可重複讀,幻讀等問題。tables 髒讀不可重複讀 幻讀read uncommitted read com...
資料庫事務隔離級別詳解
資料庫事務的隔離級別有4個,由低到高依次為read uncommitted read committed repeatable read serializable,這四個級別可以逐個解決髒讀 不可重複讀 幻讀這幾類問題。可能出現 不會出現 髒讀不可重複讀 幻讀read uncommitted rea...
資料庫 事務與隔離級別
事務概述 redo log概述 undo log概述 事務控制語句 配置引數 控制語句 事務隔離級別 隔離級別簡介 mvcc併發控制 鎖型別簡介 事務是作為單個邏輯操作單元的一系列操作。事務可以包含一條或多條sql語句,所有的語句被當做乙個操作單元,要麼全部成功 要麼全部失敗 即作為乙個原子操作 資...