淺談事務(一)

dbasdk發表於2015-05-05
關於事務,在Oracle中似乎是習以為常的,但是在學習MySQL的過程中,發現各種靈活的儲存引擎,一個很大的焦點就是對於事務的支援,足以看出事務的實現還是有一定難度的,自己在學習資料庫理論和Oracle的時候,對於事務的特性也都是一筆帶過,ACID似乎就是書本中的概念和術語,感覺太偏向理論了,但是今天在學習看書中,也借鑑了不少寶貴的經驗,重新審視來發現事務的強大和重要性。
好多書中都會提到的ACID,先來看看是怎麼說的。
原子性:Atomicity,一致性:Consistency,隔離性:Isolation,永續性:Durability
舉個例子來說明,比如使用銀行卡轉賬,給某個朋友轉賬100塊,就需要執行幾個步驟:
首先會檢視銀行卡中的餘額是否滿足條件。
其次會從銀行卡中轉出100塊,
然後對方的銀行卡中會轉入100塊。
這個例子很簡單也很明顯,
首先原子性,就是這個轉賬的過程中,轉賬操作是一個不可再分的單元了,轉賬的的操作,卡1轉出成功,卡2轉入成功,整個過程要不全部完成,要不直接回退。
其次是一致性,就是在資料庫中,事務總是從一個一致性的狀態轉換為另外一個一致性的狀態,比如我們在操作的第2步,銀行卡轉出100塊的瞬間,系統奔潰,電腦當機,你的賬戶也不會平白無故少100塊錢。因為事務最終沒有提交,所做的修改也不會儲存在資料庫中。
再次是隔離性,這個一般來說,一個事務所做的修改,對其它事務是不可見的,這一點解釋起來稍微有些困難,先放一放。
最後一點是永續性,就是在資料庫中,所做的事務變更最後都儲存在資料庫中,這一點還是從邏輯上保證的。至少在Oracle中你做了commit不會立刻寫入資料檔案,也是一個非同步的過程。

ACID確實可以保證銀行卡里不會弄丟錢,但是在邏輯層面要實現這個事務還是很困難的,從MySQL的儲存引擎的發展就能看出,InnoDB儲存引擎相比MyISAM來說,對於資源的消耗和效能會有一定的打折,但是相比來說就更加有優勢。
其中一個難點就是隔離性,在SQL標準裡面也提供了4種隔離級別,每一種級別規定了在一個事務的修改過程中,哪些在事務間是可見的,哪些是不可見的。
比如我們用sql語句來表示兩個併發的事務。
 
事務1中開始檢視餘額,有1000塊,然後向卡里轉入100塊。在這個過程中事務1還是沒有提交,是否對於事務2可見這個1100塊新餘額。

如果從生活實際來考慮是不應該的。如果對於事務2可見,則這種情況下隔離級別就是未提交讀(READ COMMITED),就是我們常說的髒讀,當然這種隔離級別的開銷是很低的,但是會導致很多問題,所以一般的在實際應用還是比較少的。
然後我們進一步思考,如果事務1在充值100塊之後,在事務沒有提交之前,對於事務2是完全不可見的,這種隔離級別就是不可重複讀,或者提交讀(READ COMMITED),Oracle中就是採用這種隔離級別的。但是在MySQL中缺預設不是這種隔離級別。
我們來看看第三種隔離級別,可重複讀(REPEATABLE READ),這個級別保證了在同一個事務中多次讀取同樣的記錄的結果是一致的。

這種情況,事務1先充值100塊,這樣餘額就是1100,事務2充值100塊,餘額就是1200,但是在事務1未提交,所以再次查詢的時候還是顯示餘額1100,這種情況就是幻讀(Phantom Read)。
最後一種是最高階別,即可序列化(SERIALIZABLE),這種情況下會強制事務序列執行,可以避免幻讀的問題,但是他會在讀取的每一行資料上都加鎖,所以可能導致大量的效能問題。這種情況下使用的場景也很少。
在Oracle中可以使用set transaction isolation level 來指定四種隔離級別。
比如未提交讀,就可以執行  
> set transaction isolation level read committed;
Transaction set.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-1619824/,如需轉載,請註明出處,否則將追究法律責任。

相關文章