簡體   English   中英

返回值,引發異常和回滾事務

[英]Return values, throw exceptions and rolling back transactions

整個“何時拋出異常或返回值”問題都被問了很多(請參閱以下內容,僅看一個示例):

檢索方法應該返回'null'還是無法產生返回值時引發異常?

我完全同意主要答案。

現在,我的問題是將上述內容應用到更復雜的系統時,在上面添加了更多上下文。 虐待嘗試使它盡可能簡短和簡單。

好的,我們有一個示例MVC PHP應用程序:

模型A:具有函數get_car($ id),該函數返回汽車對象。

控制器A具有向用戶展示汽車的簡單功能

但是,控制器B具有復雜的功能,比如說要獲得汽車,對其進行修改(例如通過模型A的設置函數之一),還需要通過整個系統中的其他模型和庫基於這些新值中的一些來更新其他表-非常復雜

我們現在進入我的問題的主要部分:

為了數據完整性,我想使用MySQL事務。 這是我遇到“最佳/最佳實踐”方案的地方。

如果找不到汽車或存在SQL錯誤,我們將編寫模型A返回FALSE。 這對Controller A很好,因為它只想知道是否有錯誤並彈出,所以我們只檢查bom的返回值-很好。

現在我們轉到控制器B。控制器B說在調用模型A函數之前進行了一些數據庫更新,我們需要回退錯誤,因此我們需要使用事務。 現在這是我解決問題的地方。 我是否將模型A保留為返回值並僅對其進行檢查,還是將其更改為引發異常,然后又必須重新編寫Controller A,因為我們現在需要捕獲異常?完成; o))我是否回滾模型的捕獲(但是我們如何知道是否使用了事務?)還是捕獲並重新拋出或允許冒泡到控制器捕獲和滾回那里嗎?

我要說的是,如果我有很多與數據庫交互的模型和控制器,我應該讓它們拋出異常,然后包裝我所有其他代碼,例如,在try catch中包裝控制器函數,以包裹曾經拋出的模型或庫函數,或者,我是否要使模型“自包含”以整理並處理自己的問題,但是如果(對於此“調用”)一個交易是開放的(根據我上面的示例,並非每次都是交易已開始...)? 如果是這種情況,我將必須使我的所有函數都返回某些內容,然后在控制器中進行檢查,因為這是唯一知道是否存在未清事務的地方。

因此,為了澄清起見,我可以使用try catch來捕獲並回滾到控制器中,這是可以的,但是如何從“進一步向下”執行此操作,例如在模型或庫函數中……可以在執行期間和事務處理期間調用還是就像自動提交普通的MySQL調用一樣?

一個解釋性的答案將是不錯的(因為我想了解我為什么要做某事),但如果沒有,則對以下解決方案(我可以看到的解決方案)的最喜歡者投幾票:

1)使所有模型和庫函數始終返回值,然后控制器可以只是bom或嘗試捕獲以在必要時回滾-但這意味着我將不得不檢查每個模型和庫函數在其所有位置的返回值被使用。

2)使所有模型和庫函數都引發異常(例如SQL錯誤),並將每個控制器(將調用模型和庫函數)包裝在try catch中,其中catch可能只是bom或在必要時回滾...

還請注意,“ bom”將用戶推送到某個地方或顯示出一個相當大的錯誤(在有人說“允許您的應用程序終止運行的不良做法之前……”,大聲笑)

希望您能從這里得到我的消息,對於長期以來的長期疑問,我們深表歉意。

預先感謝本

[“為了實現數據完整性,我想使用MySQL事務”中隱含了一個理論上的問題...因為MySQL歷來不是很ACID-PostgreSQL和Oracle都為ACID提供了更強大的支持。 但是,回到真正的問題...]

您的(1)和(2)都專注於異常與失敗返回值,但是我的印象是,這並不是處理異常,錯誤返回和開放事務的關鍵部分(某些數據庫也支持SQL異常) 。 相反,我將重點放在使事務狀態與操縱模型的函數的嵌套相關聯。 這方面的一些想法:

  • 無論如何,您可能總是會從某些庫函數獲得錯誤返回,因此讓模型A返回FALSE並沒有真正打破范式,對於錯誤返回與異常的混合也沒有特別麻煩。 但是,錯誤返回必須正確冒泡-如果它們超出了本地可解決的范圍,則將其轉換為異常。
  • 嵌套事務是讓一個控制器啟動數據庫操作並在還使用事務的應用程序中調用其他內容的最明顯方法。 這允許失敗的子子功能僅中止其自身的部分事務,並采用錯誤返回或異常方法在非SQL端將錯誤冒泡,同時關閉的子事務仍保持合理的匹配狀態。 通常這需要在數據庫外部的代碼中進行模擬(這實際上是Django所做的)。
  • 您的代碼可以啟動一個新的(可能很大的)事務,並跟蹤它已經打開的事實,以防止代碼中的子子功能試圖重新打開它。
  • 在某些數據庫中,代碼可以根據數據庫會話狀態檢測事務是否已經打開,從而使您可以檢查數據庫會話狀態,而不必在代碼中進行跟蹤。
  • 以上兩種都允許使用保存點來模擬真正的嵌套事務。
  • 必須非常小心,以避免使用隱式提交(例如CREATE TABLE)調用SQL調用。 MySQL可能比PostgreSQL更需要注意這個問題。

實現一個大事務方法的一種方法是具有高級功能,該功能可以啟動事務,然后自身調用控制器B需要執行的操作的頂部。 這使得冒泡錯誤或具有特殊的異常中止事務異常非常簡單。 如果沒有子函數失敗並且沒有捕獲到異常,則只有頂層函數會調用commit而不是中止。 子功能不會調用提交。

相反,您可以讓所有功能都注意在非SQL端(您的代碼)中實現的事務深度,盡管在某些語言中要比其他語言更難設置(例如,在Python中使用裝飾器很容易) 。 如果他們完成了交易深度為零,這將允許他們中的任何一個調用提交。

希望這可以幫助某人:-)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM