Vincent Jia 博客

          to be a better man, to be a bad man.

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            29 隨筆 :: 3 文章 :: 0 評(píng)論 :: 0 Trackbacks

          一、事務(wù)的4個(gè)基本特征 
              當(dāng)事務(wù)處理系統(tǒng)創(chuàng)建事務(wù)時(shí),將確保事務(wù)有某些特性。組件的開(kāi)發(fā)者們假設(shè)事務(wù)的特性應(yīng)該是一些不需要他們親自管理的特性。這些特性稱為ACID特性。 ACID就是:原子性(Atomicity )、一致性( Consistency )、隔離性或獨(dú)立性( Isolation)和持久性(Durabilily)。 
          1、原子性 (Atomicity ) 
              原子性屬性用于標(biāo)識(shí)事務(wù)是否完全地完成,一個(gè)事務(wù)的任何更新要在系統(tǒng)上完全完成,如果由于某種原因出錯(cuò),事務(wù)不能完成它的全部任務(wù),系統(tǒng)將返回到事務(wù)開(kāi)始前的狀態(tài)。 
          讓我們?cè)倏匆幌裸y行轉(zhuǎn)帳的例子。如果在轉(zhuǎn)帳的過(guò)程中出現(xiàn)錯(cuò)誤,整個(gè)事務(wù)將會(huì)回滾。只有當(dāng)事務(wù)中的所有部分都成功執(zhí)行了,才將事務(wù)寫(xiě)入磁盤(pán)并使變化 永久化。為了提供回滾或者撤消未提交的變化的能力,許多數(shù)據(jù)源采用日志機(jī)制。例如,SQL Server使用一個(gè)預(yù)寫(xiě)事務(wù)日志,在將數(shù)據(jù)應(yīng)用于(或提交到)實(shí)際數(shù)據(jù)頁(yè)面前,先寫(xiě)在事務(wù)日志上。但是,其他一些數(shù)據(jù)源不是關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng) (RDBMS),它們管理未提交事務(wù)的方式完全不同。只要事務(wù)回滾時(shí),數(shù)據(jù)源可以撤消所有未提交的改變,那么這種技術(shù)應(yīng)該可用于管理事務(wù)。 
          2、一致性( Consistency ) 
              事務(wù)在系統(tǒng)完整性中實(shí)施一致性,這通過(guò)保證系統(tǒng)的任何事務(wù)最后都處于有效狀態(tài)來(lái)實(shí)現(xiàn)。如果事務(wù)成功地完成,那么系統(tǒng)中所有變化將正確地應(yīng)用,系統(tǒng)處于有效狀態(tài)。如果在事務(wù)中出現(xiàn)錯(cuò)誤,那么系統(tǒng)中的所有變化將自動(dòng)地回滾,系統(tǒng)返回到原始狀態(tài)。因?yàn)槭聞?wù)開(kāi) 
          始時(shí)系統(tǒng)處于一致?tīng)顟B(tài),所以現(xiàn)在系統(tǒng)仍然處于一致?tīng)顟B(tài)。 再讓我們回頭看一下銀行轉(zhuǎn)帳的例子,在帳戶轉(zhuǎn)換和資金轉(zhuǎn)移前,帳戶處于有效狀態(tài)。如果事務(wù)成功地完成,并且提交事務(wù),則帳戶處于新的有效的狀態(tài)。如果事務(wù)出錯(cuò),終止后,帳戶返回到原先的有效狀態(tài)。 
          記住,事務(wù)不負(fù)責(zé)實(shí)施數(shù)據(jù)完整性,而僅僅負(fù)責(zé)在事務(wù)提交或終止以后確保數(shù)據(jù)返回到一致?tīng)顟B(tài)。理解數(shù)據(jù)完整性規(guī)則并寫(xiě)代碼實(shí)現(xiàn)完整性的重任通常落在 開(kāi)發(fā)者肩上,他們根據(jù)業(yè)務(wù)要求進(jìn)行設(shè)計(jì)。 當(dāng)許多用戶同時(shí)使用和修改同樣的數(shù)據(jù)時(shí),事務(wù)必須保持其數(shù)據(jù)的完整性和一致性。因此我們進(jìn)一步研究A C I D特性中的下一個(gè)特性:隔離性。 
          3、隔離性 ( Isolation) 
              在隔離狀態(tài)執(zhí)行事務(wù),使它們好像是系統(tǒng)在給定時(shí)間內(nèi)執(zhí)行的唯一操作。如果有兩個(gè)事務(wù),運(yùn)行在相同的時(shí)間內(nèi),執(zhí)行相同的功能,事務(wù)的隔離性將確保每一事務(wù)在 系統(tǒng)中認(rèn)為只有該事務(wù)在使用系統(tǒng)。 這種屬性有時(shí)稱為串行化,為了防止事務(wù)操作間的混淆,必須串行化或序列化請(qǐng)求,使得在同一時(shí)間僅有一個(gè)請(qǐng)求用于同一數(shù)據(jù)。重要的是,在隔離狀態(tài)執(zhí)行事務(wù), 系統(tǒng)的狀態(tài)有可能是不一致的,在結(jié)束事務(wù)前,應(yīng)確保系統(tǒng)處于一致?tīng)顟B(tài)。但是在每個(gè)單獨(dú)的事務(wù)中,系統(tǒng)的狀態(tài)可能會(huì)發(fā)生變化。如果事務(wù)不是在隔離狀態(tài)運(yùn)行, 它就可能從系統(tǒng)中訪問(wèn)數(shù)據(jù),而系統(tǒng)可能處于不一致?tīng)顟B(tài)。通過(guò)提供事務(wù)隔離,可以阻止這類事件的發(fā)生。在銀行的示例中,這意味著在這個(gè)系統(tǒng)內(nèi),其他過(guò)程和事 務(wù)在我們的事務(wù)完成前看不到我們的事務(wù)引起的任何變化,這對(duì)于終止的情況非常重要。如果有另一個(gè)過(guò)程根據(jù)帳戶余額進(jìn)行相應(yīng)處理,而它在我們的事務(wù)完成前就 能看到它造成的變化,那么這個(gè)過(guò)程的決策可能 
          建立在錯(cuò)誤的數(shù)據(jù)之上,因?yàn)槲覀兊氖聞?wù)可能終止。這就是說(shuō)明了為什么事務(wù)產(chǎn)生的變化,直到事務(wù)完成,才對(duì)系統(tǒng)的其他部分可見(jiàn)。隔離性不僅僅保 證多個(gè)事務(wù)不能同時(shí)修改相同數(shù)據(jù),而且能夠保證事務(wù)操作產(chǎn)生的變化直到變化被提交或終止時(shí)才能對(duì)另一個(gè)事務(wù)可見(jiàn),并發(fā)的事務(wù)彼此之間毫無(wú)影響。這就意味著 所有要求修改或讀取的數(shù)據(jù)已經(jīng)被鎖定在事務(wù)中,直到事務(wù)完成才能釋放。大多數(shù)數(shù)據(jù)庫(kù),例如SQL Server以及其他的RDBMS,通過(guò)使用鎖定來(lái)實(shí)現(xiàn)隔離,事務(wù)中涉及的各個(gè)數(shù)據(jù)項(xiàng)或數(shù)據(jù)集使用鎖定來(lái)防止并發(fā)訪問(wèn)。 
          4、持久性 (Durabilily) 
              持久性意味著一旦事務(wù)執(zhí)行成功,在系統(tǒng)中產(chǎn)生的所有變化將是永久的。應(yīng)該存在一些檢查點(diǎn)防止在系統(tǒng)失敗時(shí)丟失信息。甚至硬件本身失敗,系統(tǒng)的狀態(tài)仍能通過(guò)在日志中記錄事務(wù)完成的任務(wù)進(jìn)行重建。持久性的概念允許開(kāi)發(fā)者認(rèn)為不管系統(tǒng)以后發(fā)生了什么變化,完 
          成的事務(wù)是系統(tǒng)永久的部分。 在銀行的例子中,資金的轉(zhuǎn)移是永久的,一直保持在系統(tǒng)中。這聽(tīng)起來(lái)似乎簡(jiǎn)單,但這,依賴于將數(shù)據(jù)寫(xiě)入磁盤(pán),特別需要指出的是,在事務(wù)完全完成并提交后才寫(xiě) 入磁盤(pán)的。 所有這些事務(wù)特性,不管其內(nèi)部如何關(guān)聯(lián),僅僅是保證從事務(wù)開(kāi)始到事務(wù)完成,不管事務(wù)成功與否,都能正確地管理事務(wù)涉及的數(shù)據(jù) ,當(dāng)事務(wù)處理系統(tǒng)創(chuàng)建事務(wù) 時(shí),將確保事務(wù)有某些特性。組件的開(kāi)發(fā)者們假設(shè)事務(wù)的特性應(yīng)該是一些不需要他們親自管理的特性。 
          二、為什么需要對(duì)事務(wù)并發(fā)控制 
              如果不對(duì)事務(wù)進(jìn)行并發(fā)控制,我們看看數(shù)據(jù)庫(kù)并發(fā)操作是會(huì)有那些異常情形 
          1、丟失更新(Lost update) 
              兩個(gè)事務(wù)都同時(shí)更新一行數(shù)據(jù),但是第二個(gè)事務(wù)卻中途失敗退出,導(dǎo)致對(duì)數(shù)據(jù)的兩個(gè)修改都失效了。 
          2、臟讀(Dirty Reads) 
              一個(gè)事務(wù)開(kāi)始讀取了某行數(shù)據(jù),但是另外一個(gè)事務(wù)已經(jīng)更新了此數(shù)據(jù)但沒(méi)有能夠及時(shí)提交。這是相當(dāng)危險(xiǎn)的,因?yàn)楹芸赡芩械牟僮鞫急换貪L。 
          3、非重復(fù)讀(Non-repeatable Reads) 
             一個(gè)事務(wù)對(duì)同一行數(shù)據(jù)重復(fù)讀取兩次,但是卻得到了不同的結(jié)果。同一查詢?cè)谕皇聞?wù)中多次進(jìn)行,由于其他提交事務(wù)所做的修改或刪除,每次返回不同的結(jié)果集,此時(shí)發(fā)生非重復(fù)讀。 
          4、二類丟失更新(Second lost updates problem) 
              無(wú)法重復(fù)讀取的特例。有兩個(gè)并發(fā)事務(wù)同時(shí)讀取同一行數(shù)據(jù),然后其中一個(gè)對(duì)它進(jìn)行修改提交,而另一個(gè)也進(jìn)行了修改提交。這就會(huì)造成第一次寫(xiě)操作失效。 
          5、幻像讀(Phantom Reads) 
              事務(wù)在操作過(guò)程中進(jìn)行兩次查詢,第二次查詢的結(jié)果包含了第一次查 
          詢中未出現(xiàn)的數(shù)據(jù)(這里并不要求兩次查詢的SQL語(yǔ)句相同)。這是因?yàn)樵趦纱尾樵冞^(guò)程中有另外一個(gè)事務(wù)插入數(shù)據(jù)造成的。 
          三、數(shù)據(jù)庫(kù)的隔離級(jí)別 
             為了兼顧并發(fā)效率和異常控制,在標(biāo)準(zhǔn)SQL規(guī)范中,定義了4個(gè)事務(wù)隔離級(jí)別,(ORACLE和SQLSERER對(duì)標(biāo)準(zhǔn)隔離級(jí)別有不同的實(shí)現(xiàn) ) 
          1、未提交讀(Read Uncommitted) 
              直譯就是"讀未提交",意思就是即使一個(gè)更新語(yǔ)句沒(méi)有提交,但是別 
          的事務(wù)可以讀到這個(gè)改變.這是很不安全的。允許任務(wù)讀取數(shù)據(jù)庫(kù)中未提交的數(shù)據(jù)更改,也稱為臟讀。 
          2、提交讀(Read Committed) 
             直譯就是"讀提交",可防止臟讀,意思就是語(yǔ)句提交以后即執(zhí)行了COMMIT以后 
          別的事務(wù)就能讀到這個(gè)改變. 只能讀取到已經(jīng)提交的數(shù)據(jù)。Oracle等多數(shù)數(shù)據(jù)庫(kù)默認(rèn)都是該級(jí)別 
          3、可重復(fù)讀(Repeatable Read): 
             直譯就是"可以重復(fù)讀",這是說(shuō)在同一個(gè)事務(wù)里面先后執(zhí)行同一個(gè)查詢語(yǔ)句的時(shí)候,得到的結(jié)果是一樣的.在同一個(gè)事務(wù)內(nèi)的查詢都是事務(wù)開(kāi)始時(shí)刻一致的,InnoDB默認(rèn)級(jí)別。在SQL標(biāo)準(zhǔn)中,該隔離級(jí)別消除了不可重復(fù)讀,但是還存在幻象讀 
          4、串行讀(Serializable) 
             直譯就是"序列化",意思是說(shuō)這個(gè)事務(wù)執(zhí)行的時(shí)候不允許別的事務(wù)并發(fā)執(zhí)行. 完全串行化的讀,每次讀都需要獲得表級(jí)共享鎖,讀寫(xiě)相互都會(huì)阻塞

           

          四,隔離級(jí)別對(duì)并發(fā)的控制 
          下表是各隔離級(jí)別對(duì)各種異常的控制能力。


          LU丟失更新DR臟讀NRR非重復(fù)讀SLU二類丟失更新PR幻像讀
          未提交讀 RUYYYYY
          提交讀 RCNNYYY
          可重復(fù)讀 RRNNNNY
          串行讀 SNNNNN

           

           

          順便舉一小例。

          MS_SQL: 
          --事務(wù)一 
          set transaction isolation level serializable 
          begin tran 
          insert into test values('xxx') 
          --事務(wù)二 
          set transaction isolation level read committed 
          begin tran 
          select * from test 
          --事務(wù)三 
          set transaction isolation level read uncommitted 
          begin tran 
          select * from test 
          在查詢分析器中執(zhí)行事務(wù)一后,分別執(zhí)行事務(wù)二,和三。結(jié)果是事務(wù)二會(huì)等待,而事務(wù)三則會(huì)執(zhí)行。

          ORACLE: 
          --事務(wù)一 
          set transaction isolation level serializable; 
          insert into test values('xxx'); 
          select * from test; 
          --事務(wù)二 
          set transaction isolation level read committed--ORACLE默認(rèn)級(jí)別 
          select * from test 
          執(zhí)行事務(wù)一后,執(zhí)行事務(wù)二。結(jié)果是事務(wù)二只讀出原有的數(shù)據(jù),無(wú)視事務(wù)一的插入操作。

          MYSQL 
          查看InnoDB系統(tǒng)級(jí)別的事務(wù)隔離級(jí)別: 
          以下為引用的內(nèi)容: 
          mysql> SELECT @@global.tx_isolation; 
          +-----------------------+ 
          | @@global.tx_isolation | 
          +-----------------------+ 
          | REPEATABLE-READ   | 
          +-----------------------+ 
          1 row in set (0.00 sec) 
          查看InnoDB會(huì)話級(jí)別的事務(wù)隔離級(jí)別: 
          以下為引用的內(nèi)容: 
          mysql> SELECT @@tx_isolation; 
          +-----------------+ 
          | @@tx_isolation | 
          +-----------------+ 
          | REPEATABLE-READ | 
          +-----------------+ 
          1 row in set (0.00 sec) 
          修改事務(wù)隔離級(jí)別: 
          以下為引用的內(nèi)容: 
            mysql> set global transaction isolation level read committed; 
            Query OK, 0 rows affected (0.00 sec) 
            mysql> set session transaction isolation level read committed; 
            Query OK, 0 rows affected (0.00 sec) 
          InnoDB的可重復(fù)讀隔離級(jí)別和其他數(shù)據(jù)庫(kù)的可重復(fù)讀是有區(qū)別的,不會(huì)造成幻象讀(phantom read),所謂幻象讀,就是同一個(gè)事務(wù)內(nèi),多次select,可以讀取到其他session insert并已經(jīng)commit的數(shù)據(jù)。下面是一個(gè)小的測(cè)試,證明InnoDB的可重復(fù)讀隔離級(jí)別不會(huì)造成幻象讀。測(cè)試涉及兩個(gè)session,分別為 session 1和session 2,隔離級(jí)別都是repeateable read,關(guān)閉autocommit 
          以下為引用的內(nèi)容: 
          mysql> select @@tx_isolation; 
          +-----------------+ 
          | @@tx_isolation | 
          +-----------------+ 
          | REPEATABLE-READ | 
          +-----------------+ 
          1 row in set (0.00 sec) 
            mysql> set autocommit=off; 
            Query OK, 0 rows affected (0.00 sec) 
            session 1 創(chuàng)建表并插入測(cè)試數(shù)據(jù) 
            mysql> create table test(i int) engine=innodb; 
            Query OK, 0 rows affected (0.00 sec)

            mysql> insert into test values(1); 
            Query OK, 1 row affected (0.00 sec) 
            session 2 查詢,沒(méi)有數(shù)據(jù),正常,session1沒(méi)有提交,不允許臟讀 
            mysql> select * from test; 
            Empty set (0.00 sec) 
            session 1 提交事務(wù) 
            mysql> commit; 
            Query OK, 0 rows affected (0.00 sec) 
            session 2 查詢,還是沒(méi)有數(shù)據(jù),沒(méi)有產(chǎn)生幻象讀 
            mysql> select * from test; 
            Empty set (0.00 sec) 
          以上試驗(yàn)版本: 
          mysql> select version(); 
          +-------------------------+ 
          | version()       | 
          +-------------------------+ 
          | 5.0.37-community-nt-log | 
          +-------------------------+ 
          1 row in set (0.00 sec)

          五、并發(fā)一致性問(wèn)題的解決辦法 
          1 封鎖(Locking) 
              封鎖是實(shí)現(xiàn)并發(fā)控制的一個(gè)非常重要的技術(shù)。所謂封鎖就是事務(wù)T在對(duì)某個(gè)數(shù)據(jù)對(duì)象例如表、記錄等操作之前,先向系統(tǒng)發(fā)出請(qǐng)求,對(duì)其加鎖。加鎖后事務(wù)T就對(duì)該 數(shù)據(jù)對(duì)象有了一定的控制,在事務(wù)T釋放它的鎖之前,其它的事務(wù)不能更新此數(shù)據(jù)對(duì)象。 基本的封鎖類型有兩種:排它鎖(Exclusive locks 簡(jiǎn)記為X鎖)和共享鎖(Share locks 簡(jiǎn)記為S鎖)。 
              排它鎖又稱為寫(xiě)鎖。若事務(wù)T對(duì)數(shù)據(jù)對(duì)象A加上X鎖,則只允許T讀取和修改A,其它任何事務(wù)都不能再對(duì)A加任何類型的鎖,直到T釋放A上的鎖。這就保證了其它事務(wù)在T釋放A上的鎖之前不能再讀取和修改A。 
              共享鎖又稱為讀鎖。若事務(wù)T對(duì)數(shù)據(jù)對(duì)象A加上S鎖,則其它事務(wù)只能再對(duì)A加S鎖,而不能加X(jué)鎖,直到T釋放A上的S鎖。這就保證了其它事務(wù)可以讀A,但在T釋放A上的S鎖之前不能對(duì)A做任何修改。 
          2 封鎖協(xié)議 
              在 運(yùn)用X鎖和S鎖這兩種基本封鎖,對(duì)數(shù)據(jù)對(duì)象加鎖時(shí),還需要約定一些規(guī)則,例如應(yīng)何時(shí)申請(qǐng)X鎖或S鎖、持鎖時(shí)間、何時(shí)釋放等。我們稱這些規(guī)則為封鎖協(xié)議 (Locking Protocol)。對(duì)封鎖方式規(guī)定不同的規(guī)則,就形成了各種不同的封鎖協(xié)議。下面介紹三級(jí)封鎖協(xié)議。三級(jí)封鎖協(xié)議分別在不同程度上解決了丟失的修改、不 可重復(fù)讀和讀"臟"數(shù)據(jù)等不一致性問(wèn)題,為并發(fā)操作的正確調(diào)度提供一定的保證。下面只給出三級(jí)封鎖協(xié)議的定義,不再做過(guò)多探討。 
              1 級(jí)封鎖協(xié)議是:事務(wù)T在修改數(shù)據(jù)R之前必須先對(duì)其加X(jué)鎖,直到事務(wù)結(jié)束才釋放。事務(wù)結(jié)束包括正常結(jié)束(COMMIT)和非正常結(jié)束(ROLLBACK)。 1級(jí)封鎖協(xié)議可防止丟失修改,并保證事務(wù)T是可恢復(fù)的。在1級(jí)封鎖協(xié)議中,如果僅僅是讀數(shù)據(jù)不對(duì)其進(jìn)行修改,是不需要加鎖的,所以它不能保證可重復(fù)讀和不 讀"臟"數(shù)據(jù)。 
              2級(jí)封鎖協(xié)議是:1級(jí)封鎖協(xié)議加上事務(wù)T在讀取數(shù)據(jù)R之前必須先對(duì)其加S鎖,讀完后即可釋放S鎖。2級(jí)封鎖協(xié)議除防止了丟失修改,還可進(jìn)一步防止讀"臟"數(shù)據(jù)。 
              3級(jí)封鎖協(xié)議是:1級(jí)封鎖協(xié)議加上事務(wù)T在讀取數(shù)據(jù)R之前必須先對(duì)其加S鎖,直到事務(wù)結(jié)束才釋放。3級(jí)封鎖協(xié)議除防止了丟失修改和不讀'臟'數(shù)據(jù)外,還進(jìn)一步防止了不可重復(fù)讀。 
          六、一般處理并發(fā)問(wèn)題時(shí)的步驟: 
          1、開(kāi)啟事務(wù)。 
          2、申請(qǐng)寫(xiě)權(quán)限,也就是給對(duì)象(表或記錄)加鎖。 
          3、假如失敗,則結(jié)束事務(wù),過(guò)一會(huì)重試。 
          4、假如成功,也就是給對(duì)象加鎖成功,防止其他用戶再用同樣的方式打開(kāi)。 
          5、進(jìn)行編輯操作。 
          6、寫(xiě)入所進(jìn)行的編輯結(jié)果。 
          7、假如寫(xiě)入成功,則提交事務(wù),完成操作。 
          8、假如寫(xiě)入失敗,則回滾事務(wù),取消提交。 
          9、(7.8)兩步操作已釋放了鎖定的對(duì)象,恢復(fù)到操作前的狀態(tài)。

          轉(zhuǎn)自:http://www.cnblogs.com/tqsummer/archive/2010/07/11/1775209.html

          posted on 2011-12-07 14:11 iLinux 閱讀(570) 評(píng)論(0)  編輯  收藏 所屬分類: Database

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 平罗县| 精河县| 延安市| 新巴尔虎左旗| 科技| 衡南县| 文登市| 古田县| 平乡县| 桂东县| 马公市| 奉贤区| 上饶县| 松滋市| 琼结县| 新竹市| 阿鲁科尔沁旗| 义马市| 高台县| 明星| 定西市| 嘉鱼县| 潜山县| 平和县| 平遥县| 乌苏市| 新乡市| 泰和县| 巴林右旗| 中宁县| 浙江省| 宜兰市| 繁昌县| 华坪县| 昌图县| 咸宁市| 两当县| 松桃| 洮南市| 新乡市| 韶山市|