轉:ORA-08177: 無法連續訪問此事務處理

xingfei80發表於2012-09-04
  轉自:http://blog.csdn.net/wyzxg/article/details/4842769
  最近我們的一套總是報 ORA-08177: 無法連續訪問此事務處理,剛開始以為是系統壓力大,併發一起的,但最近發現,及時系統壓力小時,也會報這個錯誤,於是上網仔細查詢,發現下面的文章,讓我收益非淺

  今天在訊息的接受日誌中,發現一個錯誤.ORA-08177: 無法連續訪問此事務處理.

覺得有點束手無策,於是停下許多工作,開始解決此錯誤.

首先懷疑,錯誤就是併發造成.根據日誌顯示,同一秒內,處理了7,8筆資料.所以就先從這裡下手.

後根據ORA-08177在網上查處錯誤解釋.

  Cannot serialize access 不能序列訪問.說是Oracle中比較鬱悶的 錯誤.

後來找到一個重現的例子.如下:

這個問題是由oracle 事務隔離級別引起的
在一個事務中執行
update t set object_type='zl' where object_id=17286
不要 提交此事務
然後再其他事務中執行
set transaction isolation level serializable;
update t set object_type='zl' where object_id=17286

這個時候事務2 會等待事務1執行完成,提交事務1 的時候會出現上述問題。

[@more@]我把SQL改成操作的對應訊息的表,發現的確如此.但是其中最重要的一句話是set transaction isolation level serializable;就是將這個事務,序列化,如下所述:

隔離級別(isoation eve)

隔離級別定義了事務與事務之間的隔離程度。

隔離級別與併發性是互為矛盾的:隔離程度越高,資料庫的併發性越差;隔離程度越低,資料庫的併發性越好。

ANSI/ISO SQ92標準定義了一些資料庫操作的隔離級別:

  • 未提交讀(read uncommitted)
  • 提交讀(read committed)
  • 重複讀(repeatabe read)
  • 序列化(seriaizabe)

透過一些現象,可以反映出隔離級別的效果。這些現象有:

  • 更新丟失(ost update):當系統允許兩個事務同時更新同一資料是,發生更新丟失。
  • 髒讀(dirty read):當一個事務讀取另一個事務尚未提交的修改時,產生髒讀。
  • 非 重複讀(nonrepeatabe read):同一查詢在同一事務中多次進行,由於其他提交事務所做的修改或刪除,每次返回不同的結果集,此時發生非重複讀。(A transaction rereads data it has previousy read and finds that another committed transaction has modified or deeted the data. )
  • 幻 像(phantom read):同一查詢在同一事務中多次進行,由於其他提交事務所做的插入操作,每次返回不同的結果集,此時發生幻像讀。(A transaction reexecutes a query returning a set of rows that satisfies a search condition and finds that another committed transaction has inserted additiona rows that satisfy the condition. )

下面是隔離級別及其對應的可能出現或不可能出現的現象

Dirty ReadNonRepeatabe ReadPhantom Read
Read uncommittedPossiblePossiblePossible
Read committednot possiblePossiblePossible
Repeatabe readnot possiblenot possiblePossible
Seriaizabenot possiblenot possiblenot possible

ORACE的隔離級別

ORACE提供了SQ92標準中的read committed和seriaizabe,同時提供了非SQ92標準的read-ony。

read committed:

  • 這是ORACE預設的事務隔離級別。
  • 事務中的每一條語句都遵從語句級的讀一致性。
  • 保證不會髒讀;但可能出現非重複讀和幻像。

seriaizabe:(序列執行事務,併發性最小)

  • 簡單地說,seriaizabe就是使事務看起來象是一個接著一個地順序地執行。
  • 僅僅能看見在本事務開始前由其它事務提交的更改和在本事務中所做的更改。
  • 保證不會出現非重複讀和幻像。
  • Seriaizabe隔離級別提供了read-ony事務所提供的讀一致性(事務級的讀一致性),同時又允許DM操作。

如果有在seriaizabe事務開始時未提交的事務在seriaizabe事務結束之前修改了seriaizabe事務將要修改的行並進行了提交,則seriaizabe事務不會讀到這些變更,因此發生無法序列化訪問的錯誤。(換一種解釋方法:只要在seriaizabe事務開始到結束之間有其他事務對seriaizabe事務要修改的東西進行了修改並提交了修改,則發生無法序列化訪問的錯誤。)

  

ORACE在資料塊中記錄最近對資料行執行修改操作的N個事務的資訊,目的是確定本事務開始時,是否存在未提交的事務修改了本事務將要修改的行。

read-ony:

  • 遵從事務級的讀一致性,僅僅能看見在本事務開始前由其它事務提交的更改。
  • 不允許在本事務中進行DM操作。
  • read ony是seriaizabe的子集。它們都避免了非重複讀和幻像。區別是在read ony中是隻讀;而在seriaizabe中可以進行DM操作。
  • Export with CONSISTENT = Y sets the transaction to read-ony.

read committed和seriaizabe的區別和聯絡:

事務1先於事務2開始,並保持未提交狀態。事務2想要修改正被事務1修改的行。事務2等待。如果事務1回滾,則事務2(不論是read committed還是seriaizabe方式)進行它想要做的修改。如果事務1提交,則當事務2是read committed方式時,進行它想要做的修改;當事務2是seriaizabe方式時,失敗並報錯“Cannot seriaize access”,因為事務2看不見事務1提交的修改,且事務2想在事務1修改的基礎上再做修改。

即seriaizabe不允許存在事務巢狀

read committed和seriaizabe可以在ORACE並行伺服器中使用。

關於SET TRANSACTION READ WRITE:read write和read committed 應該是一樣的。在讀方面,它們都避免了髒讀,但都無法實現重複讀。雖然沒有文件說明read write在寫方面與read committed一致,但顯然它在寫的時候會加排他鎖以避免更新丟失。在加鎖的過程中,如果遇到待鎖定資源無法鎖定,應該是等待而不是放棄。這與 read committed一致。

語句級的讀一致性

  • ORACE保證語句級的讀一致性,即一個語句所處理的資料集是在單一時間點上的資料集,這個時間點是這個語句開始的時間。
  • 一個語句看不見在它開始執行後提交的修改。
  • 對於DM語句,它看不見由自己所做的修改,即DM語句看見的是它本身開始執行以前存在的資料。

事務級的讀一致性

  • 事務級的讀一致性保證了可重複讀,並保證不會出現幻像。

設定隔離級別

設定隔離級別

設定一個事務的隔離級別

  • SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  • SET TRANSACTION READ ONLY;

設定增個會話的隔離級別

  • ATER SESSION SET ISOLATION_LEVE SERIALIZABLE;
  • ATER SESSION SET ISOLATION_LEVE READ COMMITTED;

Choice of Isolation Level

Read Committed Isolation

兩種情況:(1)在事務量大、高效能的計算環境,需要更高的吞吐量和響應時間;(2)事務數少,並且發生幻影和不可重複讀的機率的比較低

Serializable Isolation

(1)適合於很少存在兩個事務同時修改同一條記錄的情況

(2)長事務以只讀為主

(3)大型資料庫並且每個短事務只修改很少的記錄

如此我就在訊息的介面中,找到執行SQL的公用方法,發現執行批次SQL的方法,這裡將執行事務的級別設定為了Serializable(序列化),就此就真相大白了,剩下的就是商討如何解決了.

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

相關文章