880 likes | 1.02k Views
交易與同步控制. 當很熱門的商業購物網站如亞馬遜購物網,有超過 100 人同時在作購書的交易動作,這時同步的控制就很重要。關聯式資料庫上鎖的動作稱為交易。交易就是由一連串的 SQL 語法組成的動作,交易的情況在於一串敘述的執行情況,分別是全部都執行,或是全都不執行,不會發生只執行一半的情況。資料庫執行緒會讓一個 Transaction( 交易 ) 執行後,才會讓另外一個執行緒執行。 Transaction( 交易 ) 是 MySQL 最近因為電子商務交易,而因此加入的功能。.
E N D
交易與同步控制 當很熱門的商業購物網站如亞馬遜購物網,有超過100人同時在作購書的交易動作,這時同步的控制就很重要。關聯式資料庫上鎖的動作稱為交易。交易就是由一連串的SQL語法組成的動作,交易的情況在於一串敘述的執行情況,分別是全部都執行,或是全都不執行,不會發生只執行一半的情況。資料庫執行緒會讓一個Transaction(交易)執行後,才會讓另外一個執行緒執行。Transaction(交易)是MySQL最近因為電子商務交易,而因此加入的功能。
在TYPE選項用來設定儲存資料表所用的格式,預設的格式為MyISAM,它並不支援交易的功能,MyISAM資料表除了交易Transaction功能外,此種格式幾乎支援所有的特性。我們可以建立一個支援交易功能的資料表BDB(它是屬於BERKELY資料庫型態),我們在建立資料表時設定其型態為TYPE=BDB。在TYPE選項用來設定儲存資料表所用的格式,預設的格式為MyISAM,它並不支援交易的功能,MyISAM資料表除了交易Transaction功能外,此種格式幾乎支援所有的特性。我們可以建立一個支援交易功能的資料表BDB(它是屬於BERKELY資料庫型態),我們在建立資料表時設定其型態為TYPE=BDB。
讀取與寫入運作。 • READ_ITEM(X)指令包含了在磁碟找尋X資料區塊的位置,並且複製X資料到主記憶體的緩衝區,最後再從緩衝區複製X資料到程式的變數X,從磁碟讀取資料。 • WRITE_ITEM(X)指令包含了在磁碟找尋X資料區塊的位置,並且複製X資料到主記憶體的緩衝區,並且從程式變數X來複製X資料到正確緩衝區的位置,最後將更新的緩衝區資料儲存到硬碟,將資料寫入磁碟。 • 一個交易包含了READ_ITEM和WRITE_ITEM運作來存取和更新資料庫。下圖的交易T1和交易T2簡單的顯示了交易。
1-1同步交易的問題 • 同步交易控制和回復機制主要和交易(Transaction)存取的機制有關。許多使用者使用購物網時,會同步的執行交易和存取的動作而且同步的更新資料庫的內容。假如同步的執行沒有控制好,將會引發許多資料不一致的問題。在下面我們將繼續研究主要的三個資料不一致問題,分別為遺漏更新資料問題、暫時更新資料問題和結果不正確的問題。 • 遺失更新資料的問題﹕ • 當兩個交易T1和交易T2同時間存取資料庫的資料而發生資料遺失的問題。當交易T1讀取資料X(60),然後再將X減去N(3),則交易T1讓X資料的值是57,這時,交易T2也開始讀取從資料庫讀取資料X(60)的值,然後再將資料X(60)的值加入M(5),此時X為56。然後又是交易T1來將資料X(57)的值寫入到資料庫中,然後再讀取資料Y的值。然後交易T2再將資料X(57)的值寫入到資料庫中。這時,交易T1被更新的資料X(57)就遺失了。
暫時更新資料的問題﹕ • 當一個交易更新資料庫的資料時,因為某些因素造成失敗,就會造成暫時更新資料的問題。在更新回去它原本的資料之前,這個暫時更新的資料被另外一個交易存取。當交易T1更新資料X,並且將X的資料寫回去資料庫,這時交易T2從資料庫讀取X的值,在完成整個交易T1前,發生了錯誤,因此系統必需改變X的值到它原來的值。在交易T1改變這個交易T1前,交易T2已經讀取了暫時更新的資料X。而資料X只是暫時性的記錄而不是永久性的記錄,因為T1交易的取消而造成。這個被交易T2所讀取的資料被稱為錯誤資料dirty data。
資料結果不正確的問題﹕ • 假如有一些交易在作大量資料的盤點或總計運算(SUM)時,有一些其它的交易正在更新一些資料,則這個盤點或總計運算資料會在更新交易的前面或更新交易的後面。假如交易T3正在計算目前書籍的庫存量(SUM),同時,交易T1也正在執行。假如下面交易T1和交易T3同時發生,則交易T3會少數量N,因為交易T3在N本書被減去時才讀取X的數值,而且在N本書加入前來讀取Y的數值。
1-1-1交易回復機制的重要性 • 當我們交易在資料庫系統DBMS執行時,這個系統必需能夠完全成功並且永久的在資料庫中記錄這交易的資料,而且這個交易必需能夠不影響到其它交易的進行。失誤可以分為交易失誤,系統或媒體失誤。當下列一些狀況在執行時也有可能產生交易的失誤。因此當交易失誤發生,交易回復的機制就會很重要。 • 電腦系統當機﹕當我們在作交易時,電腦系統當機或網路斷線而產生的交易失誤稱為電腦系統當機。 • 交易或系統發生錯誤﹕當使用者在交易時想要中斷交易,或者當交易時參數傳遞的問題發生導致整個的交易失敗,這時稱為交易或系統發生錯誤。 • 因交易而產生的例外或錯誤﹕當交易執行時,因為取消交易而發生的情況,或者當交易時,因為使用者帳戶的資金不夠,而產生交易無效的情況,這時所有的交易都要取消並回復。 • 加強同步控制﹕當好幾個交易同時進行,而產生死結,我們可以使用取消交易的方式來加強同步的控制。 • 磁碟失誤﹕一些磁碟區塊會因為讀取或寫入大量資料而產生交易資料錯誤的情況發生,這時交易的回復和資料的備份就會很重要。 • 實體問題和天災﹕當停電、大地震、火災或因天然的因素而造成交易失誤的問題。
1-2交易和系統概念 • 我們將在此講述各種交易進行的狀態。交易是一種單元性的情況,它不是被完全的執行,就是全部被取消。下列就是我們回復機制的一些功能及狀態。 • 開始交易﹕這是交易的開始。 • 讀取或寫入﹕這是指在交易當中讀取或寫入資料庫的動作。 • 結束動作﹕交易的讀取或寫入的動作完全結束。在這個點會檢查是否交易是長期性的寫入資料庫,或者交易被取消。 • 執行(COMMIT)﹕當交易信號為成功執行時,更新的動作將被安全的被執行到資料庫。 • 回到交易前的情況(ROLLBACK)﹕當交易性號為失敗,因此要回到交易前的情況,任何交易或影響到資料庫的資料必需回復到以前的狀態。 • 這是交易(Transaction)的狀態圖,這顯示了交易如何的進行。當一個交易從開始交易進入到SQL語令狀態時,它可以進行讀取和寫入的動作。當交易動作結束時,它移動到部份執行(PARTIALLY COMMITTED)的狀態。當進入到部份執行狀態時,當系統失誤則會引起取消abort到失敗failed的狀態,當檢查一切成功,則會進入到執行(committed)的狀態,並且將資料庫的資料作更新執行的動作。當在失敗的狀態,它會回到交易前的情況,再到終止的狀態。在終止後,因為失敗的交易可能會回到開始交易。
1-2-1交易 • 交易Transaction是由一個或多個SQL敘述所組成的動作,它有起點也有終點。它的起點就是開始交易,而終點有兩個,一個是放棄,一個是執行。放棄的情況都會造成ROLLBACK回到交易前的狀態,而執行COMMIT則是作執行更新資料庫的動作。一個好的交易有下列幾項特性ACID,完整性(ATOMICITY)、一致性(CONSISTENCY)、隔離性(ISOLATION)及可靠性(DURABILITY)。 • 交易的完整性﹕完整性是指交易是不可分割的,要不就全部動作都執行,要不就全部動作都不執行。 • 交易的一致性﹕資料庫藉由將交易TRANSACTION可串列化執行,以保持資料的一致性。雖然許多個交易好像是同步在執行,其時資料庫系統一次只讓一個交易在執行。 • 交易的隔離性﹕資料庫的隔離性是在正常情況下,前一個交易的結果,必需在執行COMMIT之後,才能被後一個TRANSACTION交易使用。 • 交易的可靠性﹕交易的可靠性表示交易在執行COMMIT後的結果,必需是永久的。
1-2-2系統記錄 • 資料庫把交易開始到結束之間所發生的情況與動作都記錄下來。當回復ROLLBACK一個交易時,資料庫會使用系統記錄System Log將資料回復到原先一致的情況。為了能讓因為失誤而受影響的交易回復,資料庫系統使用系統記錄檔System Log來記錄交易的過程。這個記錄檔是寫入在磁碟當中,因此它不會受到交易失誤的影響,而且我們使用系統記錄備份的方法來保護系統記錄檔。資料庫的系統記錄檔就像是我們使用作業系統,當作業系統當機時,重新開機時,就會從系統記錄檔來讀取當機時的一些作業系統記錄。我們MySQL的資料格式預設為MyISAM,它並不支援交易Transaction,因此我們在建立資料表時需定義資料表的形式為有支援交易的資料表。我們在第四行使用TYPE=BDB來設定MySQL資料庫的GOOD資料表格式為BDB。使用BERKELY資料庫資料表來支援交易(TRANSACTION)。
雖然MyISAM不支援交易,但是它的執行速度確是非常快的。下面是MySQL資料庫資料表的格式。INNODB資料表格式、BDB資料表格式為有支援交易Transaction的資料表格式。雖然MyISAM不支援交易,但是它的執行速度確是非常快的。下面是MySQL資料庫資料表的格式。INNODB資料表格式、BDB資料表格式為有支援交易Transaction的資料表格式。
1-2-3在SQL中的交易 • SQL標準語法的交易定義和我們已經定義過的交易語法類似。SQL標準語法是邏輯性的工作,並且保證交易的單一完整性。一個簡單的SQL敘述為全有或全無的運算。我們SQL語法從開始交易到最後為執行COMMIT或回復ROLLBACK。每一個交易都有其存取權限ACCESS MODE、隔離程度ISOLATION LEVEL和影響範圍大小。 • 存取權限Access Mode﹕存取權限可分為唯讀或讀寫。預設的存取權限為讀寫。當隔離層度為uncommitted被指定時則為唯讀。讀寫權限允許插入、刪除、更新和建立等指令被執行。唯讀的權限就是只有讀取資料的權限。 • 影響範圍大小﹕我們可以指定一定的範圍N來回饋我們使用者最近所執行的SQL敘述。 • 隔離程度isolation level﹕隔離程度分為READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和依序執行SERIALIZABLE。預設的隔離程度為依序執行SERIALIZABLE。依序執行SERIABLIZABLE為防止無效讀取Dirty read、防止無法重複的讀取和不確定的讀取。假如交易的隔離程度低於SERIALIZABLE依序存取,則就有可能發生資料讀取錯誤的情況發生。 • 當交易T1修改了某個資料後,便允許另一個交易T2來讀取資料,如果前一個交易T1因為某一些因素而放棄這個修改時,則後面的交易T2則會讀取到一個不存在的資料,則我們稱為無效讀取Dirty read。無效讀取只會在READ UNCOMMITTED隔離等級發生。
READ COMMITTED為限制讀取資料時只能讀取已經執行Commit過的資料,來避免無效讀取Dirty read。當交易T1正在讀取某個資料表,但是交易T2卻同時要修改資料,則當交易T1再讀取一次時,其資料和前面所讀取的資料就會不同。 • REPEATABLE READ等級會把正在被讀寫的數筆資料鎖起來,這樣其它的交易就不會存取它們,因此可以解決無法重複讀取的問題。但是其它的交易仍然能夠可以新增或修改其它的記錄,當我們第一個的交易讀取時仍然會得到不同的資料數值。 • SERIALIZABLE隔離等級會強制每個交易都依序執行,也就是當交易T1全部執行完後,交易T2才能開始執行。SERIALIZABLE也是SQL語法預設的隔離等級。當有兩個交易T1和T2要執行時,如果交易T1先執行,則交易T2會等到交易T1執行完才執行,這就是依序執行SERIALIZABLE的隔離等級。 • 我們在這下表可以看到唯有交易的隔離程度為SERIALIZABLE依序執行才不會違反交易的情況,只要交易的隔離程度低於SERIALIZABLE,則會發生資料錯誤的情況。
1-2-4交易實作 • 在MySQL中TYPE選項用來設定儲存資料表所用的格式,預設的格式為MyISAM,它並不支援交易的功能,MyISAM資料表除了交易Transaction功能外,此種格式幾乎支援所有的特性。我們可以建立一個支援交易功能的資料表BDB(它是屬於BERKELY資料庫型態),我們在建立資料表時設定其型態為TYPE=BDB。 • 我們可以在資料庫下建立一個有支援交易功能的資料表,我們在MySQL中設定資料表的型態為BDB。BDB資料表有支援交易的功能。
我們可以插入一筆新的資料進入資料表中。這筆資料叫作chaiyen。我們將在下面從BEGIN開始交易,並且將資料chaiyen更改成資料justin,然後再使用交易的回復機制將更改的資料取消,並且回復到以前的狀態。我們可以插入一筆新的資料進入資料表中。這筆資料叫作chaiyen。我們將在下面從BEGIN開始交易,並且將資料chaiyen更改成資料justin,然後再使用交易的回復機制將更改的資料取消,並且回復到以前的狀態。
我們使用update來更新資料,將資料名稱為chaiyen的更成justin。我們使用update來更新資料,將資料名稱為chaiyen的更成justin。 • 這時我們執行select指令,就可以看到資料已經被更改成justin了。
MySQL會在每一個SQL敘述後加上COMMIT執行動作,我們可以使用SET敘述和BEGIN敘述來宣告一個交易的起始點。交易只能在某幾種表格上運作,MySQL資料庫預設的MyISAM資料表並不支援交易功能。如果我們在MySQL資料庫預設的資料表MyISAM來修改資料,則SQL指令會被即刻執行,而且無法放棄這些修改並返回原來的起始點和狀態。MySQL會在每一個SQL敘述後加上COMMIT執行動作,我們可以使用SET敘述和BEGIN敘述來宣告一個交易的起始點。交易只能在某幾種表格上運作,MySQL資料庫預設的MyISAM資料表並不支援交易功能。如果我們在MySQL資料庫預設的資料表MyISAM來修改資料,則SQL指令會被即刻執行,而且無法放棄這些修改並返回原來的起始點和狀態。 • 我們使用begin來開始交易,並且使用update來更新資料。當我們更新完資料後使用commit執行,這時整個交易就作一個結束了。
我們之後使用rollback回復指令還是無法回復了。因為在begin開始交易後,我們可以使用執行commit來表示該筆交易的結束。我們之後使用rollback回復指令還是無法回復了。因為在begin開始交易後,我們可以使用執行commit來表示該筆交易的結束。 • 在交易中,我們只能使用INSERT和UPDATE敘述來修改資料表的內容,但是我們不可以修改資料表的SCHEMA架構。當我們要修改資料表的架構時,就會立即的執行,並完成目前的交易,這包含了,ALTER TABLE、BEGIN、DROP DATABASE、DROP TABLE、RENAME TABLE、CREATE INDEX等SQL指令。
1-2-5排程的可串列化性 • 排程Serializability of Schedules就是執行交易的排列過程。排程A和排程B稱為可串列化的,因為每一個交易的運作都是連貫性的執行,而沒有任何其它的交易交叉執行。在可串列化的排程serial schedule中,每一個交易都是按照次序串列化執行的。在排程A中,當交易T1執行完才會執行交易T2﹔在排程B中當交易T2執行完才會執行交易T1。排程C和排程D稱為非可串列化的排程nonserial。在串列化性的排程中,一次只有一個交易串列化的執行,而不是有其它交易穿插其中。假如我們假設每一個交易都是獨立的,則這些排程將正確無誤的被執行。串列化性的排程雖然不會發生錯誤,但是卻會限制運作的同步和交叉執行。在串列化的排程中,假如交易在等待I/O(讀取/寫入)的運作來完成,我們將很難將CPU資源轉到其它的交易,而I/O(讀取/寫入)磁碟機的運作又很花時間,因此其串列化性的交易將很沒有效率。在實際的運作上,我們將很少使用串列化的排程。 • 我們假設X=80、Y=70、N=6、M=5。當在排程A和B執行完交易T1和交易T2,我們將可以得到X=79的值和Y=76的值,這是交易正確的值。當我們在執行非串列化的排程C或D。排程C給予我們X=92的數值、Y=93的數值,而排程C所運算結果的X數值為不正確。而排程D則給我們正確的數值。
排程A的運算﹕我們假設X=80、Y=70、N=6、M=5。當交易T1先作讀取X=80 READ_ITEM(80),然後將X(80)減去N(6)得到74,再將74寫入到資料庫中WRITE_ITEM(X)。然後,再讀取Y(70),並將70加上6得到76,並且再將Y(76)寫入資料庫WRITE_ITEM(Y)。 • 當交易T1運算完後,它才會執行交易T2。交易T2讀取X(74),並將X(74)加上M(5)得到79,並將X(79)寫入資料庫中WRITE_ITEM(X)。 • 我們可以經由排程A得到X為79,Y為76。
排程B的運算﹕我們假設X=80、Y=70、N=6、M=5。當交易T2先作讀取X=80 READ_ITEM(80),然後將X(80)加上M(5)得到85,再將85寫入到資料庫中WRITE_ITEM(X)。 • 當交易T2運算完後,它才會執行交易T1。交易T1讀取X(85),並將X(85)減去N(6)得到79,並將X(79)寫入資料庫中WRITE_ITEM(X)。然後,再讀取Y(70),並將70加上6得到76,並且再將Y(76)寫入資料庫WRITE_ITEM(Y)。 • 我們可以經由排程B得到X為79,Y為76。
排程C的運算﹕我們假設X=80、Y=70、N=6、M=5。當交易T1先作讀取X=80 READ_ITEM(80),然後將X(80)減去N(6)得到74。這時交易T2開始執行讀取X(80)READ_ITEM(X),並將80加上5得到85。這時又換交易T1開始執行,交易T1將85寫入資料庫WRITE_ITEM(X),並且交易T1讀取Y(70)。這時又換到交易T2執行,將X(85)再度的寫入資料庫中。這時又換到交易T1執行將Y(70)加上N(6)得到76,並且將Y(76)寫入資料庫中。 • 我們可以經由排程C得到X為85,Y為76。我們在排程C得到錯誤的結果,因為我們交易T1在執行完READ_ITEM(X)和X=X-N後,沒有執行更新資料庫的X資料的動作,以致交易T2讀取到沒有更新的資料X,而產生交易的錯誤。
排程D的運算﹕我們假設X=80、Y=70、N=6、M=5。當交易T1先作讀取X=80 READ_ITEM(80),然後將X(80)減去N(6)得到74,再將X(74)寫入到資料庫中WRITE_ITEM(X)。然後交易T1讀取X(74),並將X(74)加上M(5)得到79,並將X(79)寫入資料庫中WRITE_ITEM(X)。然後再次執行交易T1,再讀取Y(70),並將70加上6得到76,並且再將Y(76)寫入資料庫WRITE_ITEM(Y)。 • 我們可以經由排程D得到X為79,Y為76。我們可以知到只有排程A、排程B、排程D是正確的交易排程情況。
1-2-6排程的可串列化性測試 • 我們可以使用簡單的演算法來測試這個排程的串列化性是否衝突。一般的同步控制方法是沒有用來作串列化性的測試。演算法可以用來測試可串列化性的衝突。這個演算法只有讀取資料read_item和寫入資料write_item兩種操作來建構可串列化排程圖。可串列化排程圖為有向圖directed graph。S=(N,E)。S就是我們的串列化排程圖,N={T1,T2,T3,T4,T5,,,,,Tn}為我們的節點集合,E={e1,e2,e3,,,,,em}為我們路徑的集合。在排程中,對於每一個交易Ti都有一個節點。在排程圖中,每一個路徑ei都是以(Tj→Tk)的格式出現1≦j≦n,1≦k≦n。Tj節點是路徑ei的起始點,Tk節點是路徑ei的終點。
可串列化性排程測試演算法﹕ • 1.我們設定排程圖為S • 2.對於在排程中的每一個交易Ti,在排程圖S中建立節點Ti • 3.對於每一個Tj節點執行讀取資料READ_ITEM(X)在Ti節點執行寫入資料WRITE_ITEM(X)之後,我們在排程圖S中建立Ti節點到Tj節點的路徑(Ti→Tj)。 • 4.對於每一個Tj節點執行寫入資料WRITE_ITEM(X)在Ti節點執行讀取資料READ_ITEM(X)之後,我們在排程圖中S建立Ti節點到Tj節點的路徑(Ti→Tj)。 • 5.對於每一個Tj節點執行寫入資料WRITE_ITEM(X)在Ti節點執行寫入資料WRITE_ITEM(X)之後,我們在排程圖中S建立Ti節點到Tj節點的路徑(Ti→Tj)。 • 6.如果在這個排程圖S中沒有形成迴圈,則我們稱這排程圖S為可串列化排程圖。
在排程圖中S如果形成迴圈,則我們可以稱為不可串列化性的排程。迴圈就是C=((Tj→Tk),(Tk→Ti),,,(Ti→Tj)),從Tj節點的路徑最後可以回到Tj節點。假如排程圖S沒有迴圈,我們就可以建立相等的串列化排程圖S’。在排程圖中S如果形成迴圈,則我們可以稱為不可串列化性的排程。迴圈就是C=((Tj→Tk),(Tk→Ti),,,(Ti→Tj)),從Tj節點的路徑最後可以回到Tj節點。假如排程圖S沒有迴圈,我們就可以建立相等的串列化排程圖S’。 • 我們從排程圖可以看到第三個圖形成迴圈,因此它是不可串列化性的排程圖。而其它三個圖都沒有形成迴圈,所以這三個圖是可串列化性的排程圖。
這是交易T1,交易T2和交易T3的讀取read和寫入write操作的動作。第一種排程和第二種排程的圖形分別是圖形D和圖形E。第一種排程的圖形D因為有兩個迴圈,所以它是不可串列化的排程。第二種排程的圖形E因為路徑沒有形成迴圈所以它是相等於可串列化的排程。這是交易T1,交易T2和交易T3的讀取read和寫入write操作的動作。第一種排程和第二種排程的圖形分別是圖形D和圖形E。第一種排程的圖形D因為有兩個迴圈,所以它是不可串列化的排程。第二種排程的圖形E因為路徑沒有形成迴圈所以它是相等於可串列化的排程。
我們第一種的排程可以畫成圖形D。因為圖形D形成了迴圈,所以它是不可串列化的排程。我們第一種的排程可以畫成圖形D。因為圖形D形成了迴圈,所以它是不可串列化的排程。
第二種排程的圖形E因為路徑沒有形成迴圈所以它是相當於可串列化的排程。第二種排程的圖形E因為路徑沒有形成迴圈所以它是相當於可串列化的排程。
先將所有的交易當作節點,並將節點加入排程圖S中。先將所有的交易當作節點,並將節點加入排程圖S中。 • 交易T3先開始交易READ_ITEM(Y),再READ_ITEM(Z)。然後交易T1開始交易,READ_ITEM(X),再WRITE_ITEM(X),而下面的READ_ITEM(X)為交易T2所執行,所以滿足演算法第三個條件,建立從節點T1到T2的路徑X。接下來執行交易T3的WRITE_ITEM(Y)的動作,而下面的WRITE_ITEM(Y)是由交易T1所執行,所以滿足演算法第五個條件,因此從交易T3建立到交易T1的路徑Y﹔同理,在執行交易T3的WRITE_ITEM(Y)的動作,而下面的READ_ITEM(Y)是由交易T2所執行,所以滿足演算法第三個條件,因此從交易T3建立到交易T2的路徑Y。接下來執行交易T3的WRITE_ITEM(Z)的動作,而下面的READ_ITEM(Z)是由交易T2所執行,所以滿足演算法第三個條件,因此從交易T3建立到交易T2的路徑Z。然後是交易T2的READ_ITEM(Z),沒有滿足演算法。然後是交易T1的READ_ITEM(Y)沒有滿足演算法。然後是交易T1的WRITE_ITEM(Y)滿足演算法第三個條件,其下面是接著交易T2的READ_ITEM(Y),因此繪製從交易T1到交易T2繪製路徑Y。接下來都是執行交易T2因此並沒有滿足演算法。最後,所有交易的操作都結束了,也繪製了圖形。