深入理解資料庫事務 W18

2021-08-28 01:17:40 字數 3693 閱讀 4000

transaction作為關係型資料庫的核心組成,在資料安全方面有著非常重要的作用,本文會一步步解析事務的核心特性,以獲得對事務更深的理解。

資料庫幾乎是所有系統的核心模組,它將資料有條理地儲存在儲存介質(磁碟)中,

並在邏輯上,將資料以結構化的形態呈現給使用者。支援資料的增、刪、改、查,並在過程中保障資料的正確且可靠。

要做到這點並非易事,常見的例子就是銀行轉賬,a賬戶給b賬戶轉賬乙個億(t1),買一塊地蓋房子。在這種交易的過程中,有幾個問題值得思考:

要保證交易正常可靠地進行,資料庫就得解決上面的四個問題,這也就是事務誕生的背景,它能解決上面的四個問題,對應地,它擁有四大特性:

接下來詳細地了解這四大特性:

可以看出,原子性、隔離性、一致性的根本問題,是不同的事務同時對同乙份資料(a賬戶)進行寫操作(修改、刪除、新增),如果事務中都只是讀資料的話,那麼它們可以隨意地同時進行,反正讀到的資料都是一樣的。

如果,幾個互不知曉的事務在同時修改同乙份資料,那麼很容易出現後完成的事務覆蓋了前面的事務的結果,導致不一致。 事務在最終提交之前都有可能會回滾,撤銷所有修改:

1. 如果t1事務修改了a賬戶的資料,

2. 這時t2事務讀到了更新後的a賬戶資料,並進行下一步操作,

3. 但此時t1事務卻回滾了,撤銷了對a賬戶的修改,

4. 那麼t2讀取到的a賬戶資料就是非法的,這會導致資料不一致。

這些問題都是事務需要避免的。

begin;

-- 開始乙個事務

update

table

set a = a - 1億;

-- 偽sql,僅作示意

update

table

set b = b + 1億;

-- 其他讀寫操作

commit;

-- 提交事務

要保證上面操作的原子性, 就得等begincommit之間的操作全部成功完成後,才將結果統一提交給資料庫儲存,如果途中任意乙個操作失敗,就撤銷前面的操作,且操作不會提交資料庫儲存,這樣就保證了同生共死

原子性的問題解決了,但是如果有另外的事務在同時修改資料a怎麼辦呢? 雖然可以保證事務的同生共死,但是資料一致性會被破壞。 此時需要引入資料的隔離機制,確保同時只能有乙個事務在修改a,乙個修改完了,另乙個才來修改。 這需要對資料a加上互斥鎖:

以上面的事務為例,稱作t1,t1在更新a的時候,會給a加上互斥鎖,保證同時只能有乙個事務在修改a。 那麼這個鎖什麼時候釋放呢? 當a更新完畢後,正在更新b時(t1還沒有提交),有另外乙個事務t2想要更新a,它能獲取到a的互斥鎖嗎?

答案是不能, 如果t1在更新完a後,就釋放了互斥鎖,此時t2獲取到t1的最新值,並做修改, 如果一且正常,則萬事大吉。 但是如果在t2更新a時,t1因為後面的語句執行失敗而回滾了呢?

1. 此時t1會撤銷對a的修改,

2. t2得到的a資料就是髒資料,更新髒資料就會導致資料不一致。

所以,在事務中更新某條資料獲得的互斥鎖,只有在事務提交或失敗之後才會釋放,在此之前,其他事務是只能讀,不能寫這條資料的。

接下來詳細解釋,假設有下面兩個事務同時執行

begin;

-- 事務1

insert

into table1 (somevaue);

-- 隨意寫的偽sql

update table2 set aa = aa + 1

where id = 1;

commit;

begin;

-- 事務2

select

count(*) from table1;

-- 第一次讀count

select aa from table2 where id = 1;

-- 第一次讀aa

-- 假設在這個點 事務1成功提交

select

count(*) from table1;

-- 第二次讀count

select aa from table2 where id = 1;

-- 第二次讀aa

commit;

序列化不用解釋了,依次執行,不會產生衝突。

可重複讀是什麼意思呢? 事務2執行到一半時,事務1 成功提交:

讀取已提交是什麼意思呢? 事務2執行到一半時,事務1 成功提交:

讀取未提交是什麼意思呢? 事務2執行到一半時,事務1 還未提交:

- 事務2中第二次讀count得到的值和第一次讀count得到的值不一樣(因為事務1新增了一條資料),這叫幻讀,不隔離新增的資料。

- 事務2中第一次讀aa第二次讀aa得到的值是不一樣的(事務1未提交),對最新版本的值可見,不隔離已經存在的資料。 不可以重複讀,讀到的資料是不一樣的。

- 如果此時事務1因為其他原因回滾了,事務2第二次讀到的資料是無意義的,因為修改沒有發生(回滾了),這叫髒讀

在現實環境中,序列化一般不會被使用,因為效能太低。

如果對一致性有要求,比如轉賬交易,那麼要使用可重複讀,併發效能相對較差。 原因是,為了實現可重複讀,在對更新記錄加鎖時,除了使用記錄鎖,還可能會使用間隙鎖鎖住區間(看update語句的where條件),這會增加其他事務等待時間。

如果對一致性要求不高,一般使用讀取已提交, 由於不考慮重複讀,在加鎖時一般只加記錄鎖,不會使用間隙鎖,併發性較好,據說使用的最多。

隔離性的問題解決了,但是如果在事務提交後,事務的資料還沒有真正落到磁碟上,此時資料庫奔潰了,事務對應的資料會不會丟?

事務會保證資料不會丟,當資料庫因不可抗拒的原因奔潰後重啟,它會保證:

- 成功提交的事務,資料會儲存到磁碟

- 未提交的事務,相應的資料會回滾

事務日誌

資料庫通過事務日誌來達到這個目標。 事務的每乙個操作(增/刪/改)產生一條日誌,內容組成大概如下:

磁碟上每個頁(儲存資料的,不是儲存日誌的)都記錄著最後乙個修改該資料操作的lsn。資料庫會通過解析事務日誌,將修改真正落到磁碟上(寫盤),隨後清理事務日誌(正常情況下)。

這也是資料庫在保證資料安全效能這兩個點之前的折中辦法:

折中的辦法就是:

資料庫恢復

當資料庫從崩潰中恢復時,會有以下幾個步驟:

- 解析存在的事務日誌,分析哪些事務需要回滾,哪些需要寫盤(還沒來得及寫盤,資料庫就崩潰了)。

- redo,進行寫盤。檢測對應資料所在資料頁的lsn,如果資料頁的lsn>=事務操作的lsn,說明已經寫過盤,不然進行寫盤操作。

- undo, 按照lsn倒序進行回滾

經過這幾個階段,在資料庫恢復後,可以達到奔潰前的狀態,也保證了資料的一致性。

**這裡

深入理解資料庫鎖

oracle中分為兩種模式的鎖,一種是排他鎖 x鎖 另一種是共享所 s鎖 鎖是實現併發的主要手段,在資料庫中應用頻繁,但很多都由資料庫自動管理,當事務提交後會自動釋放鎖.oracle為了使資料庫實現高度併發訪問,它使用了不同型別的鎖來管理併發會話對資料物件的操作.oracle的鎖按作用物件不同分為如...

深入理解資料庫併發控制原理

併發控制原理 事務之間的相互影響可能導致資料庫狀態的不一致,即使各個事務能保持狀態的正確性,而且也沒有任何故障發生。因此,不同事務中各個步驟的執行順序必須以某種方式進行規範。控制這些步驟的功能由dbms的排程器部件完成,而保證併發執行的事務能保持一致性的整個過程稱為併發控制。排程器的作用如圖1所示。...

mysql深入理解資料庫索引結構

1 資料庫檔案儲存的方式 資料庫檔案儲存都是以磁碟檔案儲存在系統中的,這也是資料庫能持久化儲存資料的原因。2 從資料庫讀取資料的原理 從資料庫讀取資料,先暫且不考慮從快取中讀取資料的情況,那就是從磁碟檔案中讀取資料的,我們知道從磁碟檔案中讀取資料是比較耗時的,資料庫的select操作的時間,取決於執...