Oracle事務和鎖機制


 

事務

1. 說明

  一組SQL,一個邏輯工作單位,執行時整體修改或者整體回退。

2.事務相關概念

  1)事務的提交和回滾:COMMIT/ROLLBACK

  2)事務的開始和結束

    開始事務:連接到數據庫,執行DML、DCL、DDL語句

    結束事務: 1. 執行DDL(例如CREATE TABLE),DCL(例如GRANT),系統自動執行COMMIT語句

          2. 執行COMMIT/ROLLBACK

          3. 退出/斷開數據庫的連接自動執行COMMIT語句

          4. 進程意外終止,事務自動rollback

          5. 事務COMMIT時會生成一個唯一的系統變化號(SCN)保存到事務表

  3)保存點(savepoint): 可以在事務的任何地方設置保存點,以便ROLLBACK

  4)事務的四個特性ACID :

    1. Atomicity(原子性): 事務中sql語句不可分割,要么都做,要么都不做

    2. Consistency(一致性) : 指事務操作前后,數據庫中數據是一致的,數據滿足業務規則約束(例如賬戶金額的轉出和轉入),與原子性對應。

    3. Isolation(隔離性):多個並發事務可以獨立運行,而不能相互干擾,一個事務修改數據未提交前,其他事務看不到它所做的更改。

    4. Durability(持久性):事務提交后,數據的修改是永久的。

  5) 死鎖:當兩個事務相互等待對方釋放資源時,就會形成死鎖,下面章節詳細分析

事務隔離級別

1 .兩個事務並發訪問數據庫數據時可能存在的問題

  1. 幻想讀:

    事務T1讀取一條指定where條件的語句,返回結果集。此時事務T2插入一行新記錄並commit,恰好滿足T1的where條件。然后T1使用相同的條件再次查詢,結果集中可以看到T2插入的記錄,這條新紀錄就是幻想。

  2. 不可重復讀取:

    事務T1讀取一行記錄,緊接着事務T2修改了T1剛剛讀取的記錄並commit,然后T1再次查詢,發現與第一次讀取的記錄不同,這稱為不可重復讀。 

  3. 臟讀:

    事務T1更新了一行記錄,還未提交所做的修改,這個T2讀取了更新后的數據,然后T1執行回滾操作,取消剛才的修改,所以T2所讀取的行就無效,也就是臟數據。

2.oracle事務隔離級別

oracle支持的隔離級別:(不支持臟讀)

READ COMMITTED--不允許臟讀,允許幻想讀和不可重復讀


SERIALIZABLE--以上三種都不允許

sql標准還支持READ UNCOMMITTED (三種都允許)和 REPEATABLE READ(不允許不可重復讀和臟讀,只允許幻想讀)

以上區別在下面章節事務建立,隔離級別分析中說明

以上內容引用自:http://www.cnblogs.com/wishyouhappy/p/3698152.html

1.什么是事務,事務的特性是什么?

事務的任務便是使數據庫從一種狀態變換成為另一種狀態,這不同於文件系統,它是數據庫所特用的。它的特性有四個:TOM總結為ACID
原子性atomicity:語句級原子性,過程級原子性,事務級原子性
一致性consistency:狀態一致,同一事務中不會有兩種狀態
隔離性isolation:事務間是互相分離的互不影響(這里可能也有自治事務)
持久性durability:事務提交了,那么狀態就是永久的

所謂死鎖: 是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。 由於資源占用是互斥的,當某個進程提出申請資源后,使得有關進程在無外力協助下,永遠分配不到必需的資源而無法繼續運行,這就產生了一種特殊現象死鎖。
關於數據庫死鎖的檢查方法
一、數據庫死鎖的現象
程序在執行的過程中,點擊確定或保存按鈕,程序沒有響應,也沒有出現報錯。
二、死鎖的原理
當對於數據庫某個表的某一列做更新或刪除等操作,執行完畢后該條語句不提
交,另一條對於這一列數據做更新操作的語句在執行的時候就會處於等待狀態,
此時的現象是這條語句一直在執行,但一直沒有執行成功,也沒有報錯。
 
死鎖的解決方法
一般情況下,只要將產生死鎖的語句提交就可以了,但是在實際的執行過程中。用戶可能不知道產生死鎖的語句是哪一句。可以將程序關閉並重新啟動就可以了。經常在Oracle的使用過程中碰到這個問題,所以也總結了一點解決方法。

  數據庫是一個多用戶使用的共享資源,比如一個用戶表t_user,兩個瀏覽器前面的人登錄了同個一個賬號,把電話號碼改了。當多個用戶並發地存取數據時,在數據庫中就會產生多個事務同時存取同一數據的情況。若對並發操作不加控制就可能會讀取和存儲不正確的數據,破壞數據庫的一致性(臟讀,不可重復讀,幻讀等),可能產生死鎖。為了解決這個問題,加鎖是一個非常重要的技術,對實現數據庫並發控制是一個好的方案。簡單說,當一個執行sql語句的事務想要操作表記錄之前,先向數據庫發出請求,對你訪問的記錄集加鎖,在這個事務釋放這個鎖之前,其他事務不能對這些數據進行更新操作。
行級鎖和表級鎖是根據鎖的粒度來區分的,行記錄,表都是資源,鎖是作用在這些資源上的。如果粒度比較小(比如行級鎖),可以增加系統的並發量但需要較大的系統開銷,會影響到性能,出現死鎖,,因為粒度小則操作的鎖的數量會增加;如果作用在表上,粒度大,開銷小,維護的鎖少,不會出現死鎖,但是並發是相當昂貴的,因為鎖定了整個表就限制了其它事務對這個表中其他記錄的訪問。
鎖包括行級鎖、表級鎖、悲觀鎖、樂觀鎖
行級鎖:一種它鎖,防止另外事務修改此行;在使用以下語句時,Oracle會自動應用行級鎖:INSERT、UPDATE、DELETE、SELECT … FOR UPDATE [OF columns] [WAIT n | NOWAIT];SELECT … FOR UPDATE語句允許用戶一次鎖定多條記錄進行更新.使用commit或者rollback釋放鎖。 特點:開鎖大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,並發度也最高。適合於有大量按索引更新少量不同數據,同時又有並發查詢的應用,如一些在線事務處理系統。
表級鎖:5種
 共享鎖(SHARE) - 鎖定表,對記錄只讀不寫,多個用戶可以同時在同一個表上應用此鎖,在表沒有被任何DML操作時,多個事務都可加鎖,但只有在僅一個事務加鎖的情況下只有此事務才能對表更新;當表已經被更新或者指定要更新時(select for update),任何事務都不能加此鎖了。
共享行排他(SHARE ROW EXCLUSIVE) – 比共享鎖更多的限制,禁止使用共享鎖及更高的鎖,在表沒有被任何DML操作時,只有一個事務可以加鎖,可以更新,書上說別的事務可以使用select for update鎖定選中的數據行,可是實驗后沒被驗證。
   排他(EXCLUSIVE) – 限制最強的表鎖,僅允許其他用戶查詢該表的行。禁止修改和鎖定表
 行共享 (ROW SHARE) – 禁止排他鎖定表,與行排他類似,區別是別的事務還可以在此表上加任何排他鎖。(除排他(exclusive)外)
   行排他(ROW EXCLUSIVE) – 禁止使用排他鎖和共享鎖,其他事務依然可以並發地對相同數據表執行查詢,插入,更新,刪除操作,或對表內數據行加鎖的操作,但不能有其他的排他鎖(自身是可以的,沒發現有什么用)
 

 悲觀鎖:

   Pessimistic Lock正如其名,它指的是對數據被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守悲觀態度,事務每次去操作數據的時候都假設有其他事務會修改需要訪問的數據,所以在訪問之前都要求上鎖,行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖,因此,在整個數據處理過程中,將數據處於鎖定狀態。
 一個典型的倚賴數據庫的悲觀鎖調用: select * from account where name=”Erica” for update 這條sql 語句鎖定了account 表中所有符合檢索條件(name=”Erica”)的記錄。 本次事務提交之前(事務提交時會釋放事務過程中的鎖),外界無法修改這些記錄。
 

樂觀鎖:

   Optimistic Lock,和悲歡鎖相反,事務每次去操作數據之前,都假設其他事務不會修改這些需要訪問的數據 ,所以 在訪問之前不要求上鎖,只是在進行更新修改操作的時候判斷一下在訪問的期間有沒有其他人修改數據 了。它適用於多讀的應用類型,沖突真的發生比較少的時候就比較好,這樣省去了開銷的開銷,可以提高吞吐量;但如果是真的經常要發生沖突的,那每次還要去判斷進行retry,反倒降低的性能,這個時候悲歡鎖比較好。數據庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。
 

1.利潤表t_profit中有一個 version字段,當前值為1;而總資產余額字段(balance)為$10000

       2.操作員A讀出version=1,從總資產減除2000,10000-2000=8000.

       3.A還沒操作結束,此時操作員B也讀出version=1,總資產減除5000,10000-5000=5000.

       4.A操作完成,把version加1,修改為2,把總資產減2000后提交更新數據庫,更新成功

       5.B操作了,也加version加1,修改為2,把總資產減5000后提交更新數據庫,此時發現version已經為2了,如B修改后加1的version一樣,不滿足樂觀鎖策略:"提交的版本必有大於記錄當前的版本才能執行"。因此B的操作請求被駁回,這樣就避免了B就version=1的舊數據修改的結果覆蓋了A操作的結果的可能。如沒有樂觀鎖,那A減去2000后剩余8000,但B操作的時候是用10000-5000剩余5000的,如果B的提交成功,總資產余額就是5000,但實際情況應該是8000-5000=3000的。出現總資產表記錄和實際支出不一致。

 

 

SQL> select * from t_book;
 
BOOKID BOOKNAME                                           PUBLISH
------ -------------------------------------------------- --------------------------------------------------
1      OracleTestForMine                                  ShenZhenPublish
2      JavaOKa                                            JiXieGongYePublish
 
SQL> savepoint a1;
 
Savepoint created
 
SQL> delete from t_book where bookid='2';
 
1 row deleted
 
SQL> select * from t_book;
 
BOOKID BOOKNAME                                           PUBLISH
------ -------------------------------------------------- --------------------------------------------------
1      OracleTestForMine                                  ShenZhenPublish
 
SQL> rollback to a1;
 
Rollback complete
 
SQL> select * from t_book;
 
BOOKID BOOKNAME                                           PUBLISH
------ -------------------------------------------------- --------------------------------------------------
1      OracleTestForMine                                  ShenZhenPublish
2      JavaOKa                                            JiXieGongYePublish
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM