【PB】PB程式死結問題及預防

來源:互聯網
上載者:User
最近一段時間由於項目的原因,和程式的“死結”問題打了不少交道。由於對“死結”定義不清楚,缺乏大批量資料處理的經驗,耗費了很多時間和精力,也走了相當多的彎路。經過摸索,對程式中出現的問題有了一定的認識,基本解決了程式中出現的各種“死結”問題。在此,對前段時間的摸索做一下經驗總結。在SQL Server2000的聯機叢書中,是這樣定義“死結”的:當某組資源的兩個或多個線程之間有迴圈相關性時,將發生死結。這裡面有一個關鍵字需要注意——“迴圈”。也就是說,真正意義上的“死結”必然存在著循環參考。A需要的資源B正使用中,因此A不能提交;然而B也在等待著A提交以便釋放B所需要的資源,才會發生“死結”。其實這種循環參考不只是在關聯式資料庫管理系統中存在,作業系統中也同樣存在。而今天我們要討論的不是這種“死結”,而是“阻塞”。 也就是當一個事務鎖定了另一個事務需要的資源,第二個事務等待鎖被釋放,這種情況下,第二個事務是被“阻塞”了而不是形成了“死結”,但由於這種情況下,第二個以上的事務無法正常繼續運行,類似於“死結”的狀態,必然影響了程式正常運行。這時,如果開啟SQL
Server的企業管理器,依次展開伺服器節點的“管理”-“當前活動”-“鎖/進程 ID”可以看到阻塞和被阻塞的進程上有醒目的紅色標記。這時,除非執行第一個事務的程式退出,否則第二個事務一直處於等待狀態,形同死機。我們的系統遇到的“死結”一般屬於這種情況。根據上面的描述,我們不難理解“阻塞”的原因。不妨做個比喻,如果一個人(事務)要去上廁所,廁所裡有一定數量的馬桶(表或其它資源),這個人上廁所佔用了一個馬桶,這就是“鎖”定了一個“表”,那麼後進來的人肯定不能使用該馬桶,除非等到這個人離開。如果這個人一直長時間不離開(有點可笑,但確實很多時候是由我們自己的失誤造成),那必然導致後續一系列矛盾衝突的發生了。由此可見,“鎖”是正常的,資料庫的機制決定了要保證資料的完整性就必然產生鎖定和釋放的現象,鎖並不可怕,鎖定表並沒有問題,但如果鎖定資源一直不釋放,那就有可能產生阻塞(甚至產生死結)。那麼這種阻塞是如何造成的呢?總結起來無非是以下幾點:1)程式的漏洞。在PB編程中,我們一般通過資料視窗與資料庫互動,有時也會直接使用嵌入式SQL語句直接操作資料庫。資料視窗執行了Update方法後,我們必鬚根據其傳回值來決定是否進行提交(Commit)或復原(Rollback)才能真正結束這個事務,釋放操作所鎖定的表或記錄。這是很明顯的道理,但在很多情況下,我們還是會犯這種似乎是不應該犯的錯誤。比如:A.寫錯了事務對象。本來是應該提交A事務對象,寫成了B或者忘記寫(不寫PB會將其預設成SQLCA事務對象)。由於我們的518系統牽涉到三個事務對象(ERP_SYS_MESSAGE、ERP_SET_MESSAGE、SQLCA),因此如果不注意的話就會犯這種錯誤。B.在函數嵌套情況下忽略了交易處理,或對IF判斷語句路徑的處理不嚴密。例如,在主程式中,我們調用了一個函數,此函數中有對資料庫進行Update的操作,依程式員本意來講,他沒有在函數中做提交或復原,是希望在主程式中統一進行提交。不幸的是,主程式中卻是根據資料視窗是否有更新來決定是否提交的,如果資料視窗有更新情況下,Update,成功則提交,失敗則復原。這似乎沒有問題,然而如果使用者一進來直接就執行主程式,並未對資料視窗操作呢?這樣自然在調用函數中執行了語句,鎖定了表,由於後面判斷資料視窗並未更改,因此也沒有提交或復原操作。這是比較奇怪的鎖表現象之一。C.函數阻斷執行問題。這也是比較常見的、初學者易犯的錯誤之一。基本情況是:判斷SQLCA的傳回值是否為-1,如果為-1表示出錯,這時,如果不掌握事務的知識,就會寫一個MessageBox函數,提示使用者相關出錯資訊,然後Rollback……一般情況下這不會出現問題,關鍵問題是,MessageBox是一個隔離型的函數,所謂隔離型是說如果Messagebox這個函數調出的對話方塊沒有被響應,那麼它就會一直阻止程式向下執行。如果正好這個操作是一個耗時較長的操作(如物料需求運算),而使用者又離開了電腦,不能及時響應這個對話方塊。系統就會一直處於等待狀態,而不會復原。相關的表資源也就一直處於佔用狀態。再有第二個事務進入時,阻塞產生。2)SQL Server本身對鎖處理的問題。說到這裡要談一下鎖的“粒度”。SQL Server具有多粒度鎖定,允許一個事務鎖定不同類型的資源。為了使鎖定的成本減至最少,SQL Server自動將資源鎖定在適合任務的層級。鎖定在較小的粒度(例如行)可以增加並發但需要較大的開銷,因為如果鎖定了許多行,則需要控制更多的鎖。鎖定在較大的粒度(例如表)就並發而言是相當昂貴的,因為鎖定整個表限制了其它事務對錶中任意部分進行訪問,但要求的開銷較低,因為需要維護的鎖較少。按照粒度增加順序依次為:RID(行標識符)、鍵、頁、擴充盤區、表、DB。一般情況下,使用SQL語句 讀取資料時(或使用資料視窗的Retrieve方法提取資料),用到的是頁級或行級鎖。也就是說它讀完一頁就會釋放再讀下一頁。但如果對一些資料量比較大的表,出現的鎖比較多,SQL
Server會自動升級為表級鎖,對整個表進行鎖定。這也沒什麼問題。關鍵是在有些情況下(目前不知道是哪個版本解決的),SQL Server會升級表鎖而用完不釋放!這就會產生問題,遇到這種情況,可考慮給SQL Server打SP4補丁,經實驗打上Sp4後不再出現讀取資料鎖表問題。3)隔離等級設定問題。事務準備接收不一致資料的層級稱為隔離等級。隔離等級是一個事務必須與其它事務進行隔離的程度。較低的隔離等級可以增加並發,但代價是降低資料的正確性。相反,較高的隔離等級可以確保資料的正確性,但可能對並發產生負面影響。應用程式要求的隔離等級確定了SQL Server使用的鎖定行為。SQL-92定義了“未提交讀”、“提交讀”、“可重複讀”、“可串列讀”四種隔離等級,SQL
Server支援這四種層級(關於這些隔離等級的論述參考SQL Server的聯機叢書),並預設為“提交讀”。在這種隔離等級下,正常的讀取操作是不會鎖定表的,但是如果在SQLCA的Lock屬性中指定了更嚴格的隔離等級,就可能導致在讀取過程中一直鎖定整個表造成其它事務的等待(有時這也是必須的)。在Select語句後使用Holdlock關鍵字也會顯式地指定資料庫在讀取資料期間鎖定整個表。預設情況下,SQLCA的Lock屬性不用修改,但如果懷疑是這個屬性出了問題,可在PB中調試時檢驗Lock屬性值是不是被修改。(Lock=‘RC’是針對SQL
Server的預設值)。以上總結了程式中可能遇到的幾種造成資源佔用和阻塞的情況。對這些情況有了清晰的瞭解後我們就很容易進行防範了。首先還是編程的邏輯要嚴謹,避免一時疏忽造成的程式錯誤;其次,採用統一的編程風格、養成良好的編程習慣也有助於發現和解決鎖表問題。最後就是SQL Server的版本及事務對象的隔離等級設定(一般不太常見,但資料量較大時應多加註意)。最後說明一點,“死結”——我們所說的阻塞,並不可怕,也並不是多麼難以解決的技術問題,遇到情況應當冷靜思考,仔細分析,最好能夠結合SQL Server企業管理器及事件探查器多試幾次,如果能通過實驗找到在什麼情況下、做了什麼操作才導致系統阻塞,在程式中修改起來也就容易得多了。最近一段時間由於項目的原因,和程式的“死結”問題打了不少交道。由於對“死結”定義不清楚,缺乏大批量資料處理的經驗,耗費了很多時間和精力,也走了相當多的彎路。經過摸索,對程式中出現的問題有了一定的認識,基本解決了程式中出現的各種“死結”問題。在此,對前段時間的摸索做一下經驗總結。在SQL Server2000的聯機叢書中,是這樣定義“死結”的:當某組資源的兩個或多個線程之間有迴圈相關性時,將發生死結。這裡面有一個關鍵字需要注意——“迴圈”。也就是說,真正意義上的“死結”必然存在著循環參考。A需要的資源B正使用中,因此A不能提交;然而B也在等待著A提交以便釋放B所需要的資源,才會發生“死結”。其實這種循環參考不只是在關聯式資料庫管理系統中存在,作業系統中也同樣存在。而今天我們要討論的不是這種“死結”,而是“阻塞”。 也就是當一個事務鎖定了另一個事務需要的資源,第二個事務等待鎖被釋放,這種情況下,第二個事務是被“阻塞”了而不是形成了“死結”,但由於這種情況下,第二個以上的事務無法正常繼續運行,類似於“死結”的狀態,必然影響了程式正常運行。這時,如果開啟SQL
Server的企業管理器,依次展開伺服器節點的“管理”-“當前活動”-“鎖/進程 ID”可以看到阻塞和被阻塞的進程上有醒目的紅色標記。這時,除非執行第一個事務的程式退出,否則第二個事務一直處於等待狀態,形同死機。我們的系統遇到的“死結”一般屬於這種情況。根據上面的描述,我們不難理解“阻塞”的原因。不妨做個比喻,如果一個人(事務)要去上廁所,廁所裡有一定數量的馬桶(表或其它資源),這個人上廁所佔用了一個馬桶,這就是“鎖”定了一個“表”,那麼後進來的人肯定不能使用該馬桶,除非等到這個人離開。如果這個人一直長時間不離開(有點可笑,但確實很多時候是由我們自己的失誤造成),那必然導致後續一系列矛盾衝突的發生了。由此可見,“鎖”是正常的,資料庫的機制決定了要保證資料的完整性就必然產生鎖定和釋放的現象,鎖並不可怕,鎖定表並沒有問題,但如果鎖定資源一直不釋放,那就有可能產生阻塞(甚至產生死結)。那麼這種阻塞是如何造成的呢?總結起來無非是以下幾點:1)程式的漏洞。在PB編程中,我們一般通過資料視窗與資料庫互動,有時也會直接使用嵌入式SQL語句直接操作資料庫。資料視窗執行了Update方法後,我們必鬚根據其傳回值來決定是否進行提交(Commit)或復原(Rollback)才能真正結束這個事務,釋放操作所鎖定的表或記錄。這是很明顯的道理,但在很多情況下,我們還是會犯這種似乎是不應該犯的錯誤。比如:A.寫錯了事務對象。本來是應該提交A事務對象,寫成了B或者忘記寫(不寫PB會將其預設成SQLCA事務對象)。由於我們的518系統牽涉到三個事務對象(ERP_SYS_MESSAGE、ERP_SET_MESSAGE、SQLCA),因此如果不注意的話就會犯這種錯誤。B.在函數嵌套情況下忽略了交易處理,或對IF判斷語句路徑的處理不嚴密。例如,在主程式中,我們調用了一個函數,此函數中有對資料庫進行Update的操作,依程式員本意來講,他沒有在函數中做提交或復原,是希望在主程式中統一進行提交。不幸的是,主程式中卻是根據資料視窗是否有更新來決定是否提交的,如果資料視窗有更新情況下,Update,成功則提交,失敗則復原。這似乎沒有問題,然而如果使用者一進來直接就執行主程式,並未對資料視窗操作呢?這樣自然在調用函數中執行了語句,鎖定了表,由於後面判斷資料視窗並未更改,因此也沒有提交或復原操作。這是比較奇怪的鎖表現象之一。C.函數阻斷執行問題。這也是比較常見的、初學者易犯的錯誤之一。基本情況是:判斷SQLCA的傳回值是否為-1,如果為-1表示出錯,這時,如果不掌握事務的知識,就會寫一個MessageBox函數,提示使用者相關出錯資訊,然後Rollback……一般情況下這不會出現問題,關鍵問題是,MessageBox是一個隔離型的函數,所謂隔離型是說如果Messagebox這個函數調出的對話方塊沒有被響應,那麼它就會一直阻止程式向下執行。如果正好這個操作是一個耗時較長的操作(如物料需求運算),而使用者又離開了電腦,不能及時響應這個對話方塊。系統就會一直處於等待狀態,而不會復原。相關的表資源也就一直處於佔用狀態。再有第二個事務進入時,阻塞產生。2)SQL Server本身對鎖處理的問題。說到這裡要談一下鎖的“粒度”。SQL Server具有多粒度鎖定,允許一個事務鎖定不同類型的資源。為了使鎖定的成本減至最少,SQL Server自動將資源鎖定在適合任務的層級。鎖定在較小的粒度(例如行)可以增加並發但需要較大的開銷,因為如果鎖定了許多行,則需要控制更多的鎖。鎖定在較大的粒度(例如表)就並發而言是相當昂貴的,因為鎖定整個表限制了其它事務對錶中任意部分進行訪問,但要求的開銷較低,因為需要維護的鎖較少。按照粒度增加順序依次為:RID(行標識符)、鍵、頁、擴充盤區、表、DB。一般情況下,使用SQL語句 讀取資料時(或使用資料視窗的Retrieve方法提取資料),用到的是頁級或行級鎖。也就是說它讀完一頁就會釋放再讀下一頁。但如果對一些資料量比較大的表,出現的鎖比較多,SQL
Server會自動升級為表級鎖,對整個表進行鎖定。這也沒什麼問題。關鍵是在有些情況下(目前不知道是哪個版本解決的),SQL Server會升級表鎖而用完不釋放!這就會產生問題,遇到這種情況,可考慮給SQL Server打SP4補丁,經實驗打上Sp4後不再出現讀取資料鎖表問題。3)隔離等級設定問題。事務準備接收不一致資料的層級稱為隔離等級。隔離等級是一個事務必須與其它事務進行隔離的程度。較低的隔離等級可以增加並發,但代價是降低資料的正確性。相反,較高的隔離等級可以確保資料的正確性,但可能對並發產生負面影響。應用程式要求的隔離等級確定了SQL Server使用的鎖定行為。SQL-92定義了“未提交讀”、“提交讀”、“可重複讀”、“可串列讀”四種隔離等級,SQL
Server支援這四種層級(關於這些隔離等級的論述參考SQL Server的聯機叢書),並預設為“提交讀”。在這種隔離等級下,正常的讀取操作是不會鎖定表的,但是如果在SQLCA的Lock屬性中指定了更嚴格的隔離等級,就可能導致在讀取過程中一直鎖定整個表造成其它事務的等待(有時這也是必須的)。在Select語句後使用Holdlock關鍵字也會顯式地指定資料庫在讀取資料期間鎖定整個表。預設情況下,SQLCA的Lock屬性不用修改,但如果懷疑是這個屬性出了問題,可在PB中調試時檢驗Lock屬性值是不是被修改。(Lock=‘RC’是針對SQL
Server的預設值)。以上總結了程式中可能遇到的幾種造成資源佔用和阻塞的情況。對這些情況有了清晰的瞭解後我們就很容易進行防範了。首先還是編程的邏輯要嚴謹,避免一時疏忽造成的程式錯誤;其次,採用統一的編程風格、養成良好的編程習慣也有助於發現和解決鎖表問題。最後就是SQL Server的版本及事務對象的隔離等級設定(一般不太常見,但資料量較大時應多加註意)。最後說明一點,“死結”——我們所說的阻塞,並不可怕,也並不是多麼難以解決的技術問題,遇到情況應當冷靜思考,仔細分析,最好能夠結合SQL Server企業管理器及事件探查器多試幾次,如果能通過實驗找到在什麼情況下、做了什麼操作才導致系統阻塞,在程式中修改起來也就容易得多了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.