簡體   English   中英

哪個更好-事先拋出異常或檢查錯誤

[英]Which is better - Throwing an Exception or Checking for errors beforehand

在連接到PostgreSQL的服務器上,我應該通過執行"select * ..."檢查用戶名是否已存在於表中,然后獲取結果集中的行數,而我的行數等於零,然后輸入用戶名?
或者只是將用戶名插入表中。 如果已經存在,則將引發錯誤,然后可以將其捕獲。
注意:用戶名是主鍵

做以上兩個中的哪一個更好?

您只應執行“嘗試並捕獲異常”方法,因為無論如何都必須這樣做。

如果您先檢查,沒有什么可以阻止某人在您的支票和插入之間為該用戶插入一行,在這種情況下,即使您的支票沒有找到,該用戶也會在表中。

缺少能夠在某種事務中運行檢查和插入的功能(因此,沒有其他人可以在過渡期間插入該用戶)。 您無法確定非例外是否有效。

雖然許多DBMS”提供的事務支持,我不知道有什么會鎖定您還沒有插入:-)行

當然,如果應用程序的設計方式是只有您的進程將插入用戶(並進行序列化),則可以使用check-first方法。 但是我要發表很多評論,以至於如果您擴大規模,就需要重新考慮它。

通常的共識是僅將例外用於例外情況,而不將其用作控制流構造。 在我看來,嘗試使用碰巧采用的用戶名應該被認為是有效的,而不是不常見的用例。

換句話說,我將首先檢查現有的用戶名。

正如@paxdiablo指出的那樣,如果您處於多線程環境(例如Web服務器)中,那么您要么需要添加一些鎖定方案,要么仍然使用try / catch方法(考慮到兩個線程可能在爭用添加相同的用戶名的競爭。 )。 但是,可以將這種情況視為例外情況。

相關問題 (所有結論相同,對於非例外情況請勿使用例外):

在這種情況下,答案都不是 既不會引發錯誤,也不會事先檢查。 那么居多 ,反正。
它可以更簡單地處理-同時又安全又快捷:

INSERT INTO users(username, col1)
SELECT 'max', 'val1'
WHERE  NOT EXISTS (SELECT * FROM users WHERE username = 'max')

僅當新用戶不存在時,它才會插入。 PostgreSQL將命令狀態設置為0 rows affected0 rows affected 1 row affected ,具體取決於它是否已存在。 無論哪種方式,聲明之后都會在那兒。

如果您想返回答案:

INSERT INTO users(username, col1)
SELECT 'max', 'val1'
WHERE  NOT EXISTS (SELECT * FROM users WHERE username = 'max')
RETURNING username;

僅當用戶名不存在時,它將返回該用戶名。
但是,該操作不是原子操作,因此,如果您有很多並發,請按以下方式獲取表上的鎖:

BEGIN;
LOCK TABLE users IN SHARE MODE;

INSERT INTO users(username, col1)
SELECT 'max', 'val1'
WHERE  NOT EXISTS (SELECT * FROM users WHERE username = 'max')
RETURNING username;

COMMIT;

請注意,即使發生的可能性很小,這仍然可能會失敗-例如,如果另一個事務由於某些錯誤而鎖定了表並永遠阻止了您。
因此,誠然,您仍然需要代碼來處理錯誤情況。 除非您的數據庫或應用程序有問題,否則它永遠不會發生。

我要說的是,在這種情況下捕獲異常就是對異常概念的濫用,如果您之前可以進行檢查,則應該對其進行檢查。

絕對不要使用異常來控制程序的流程。 最好的做法是避免例外(如果不是特殊情況)。

我寧願通過查詢而不是使用異常來檢查用戶是否存在。 “用戶存在”錯誤的邏輯很快將成為業務規則。 (好吧,您可以在SQL中編寫這樣的規則,但這是完全不同的世界)

或者只是將用戶名插入表中。 如果已經存在,則將引發錯誤,然后可以將其捕獲

問題是還有許多其他異常原因。 無論如何,您都必須處理它們。

您將獲得許多答案,其中包括“永遠不要將異常用於控制程序流”和“異常不用於控制流”。 確實,您已經有幾個。 您可能像我一樣,發現這些陳述完全沒有意義。 異常確實控制程序的流程,當設計API引發異常時,您別無選擇,只能相應地使用它。 EOFException就是一個例子。 調用引發它的方法時,您沒有其他任何方法可以檢測到EOS。

在這種情況下,適用不同的原理。 如果進行測試然后進行設置,那么您將引入一個計時窗口,在此期間后續設置可能會失敗,並且如果設置操作會引發異常,則無論如何都必須為其編寫代碼。 在這些情況下,您應該只進行設置並相應地處理異常。 這樣,您的操作是原子的,您不必兩次編寫相同的代碼。 通常,檢測資源是否可用的最可靠方法是嘗試使用它(考慮連接到網絡服務器),而檢測操作是否失敗的最可靠方法是實際嘗試(考慮這種情況,例如,將值插入其中是唯一鍵的數據結構中。

有關“永遠不要使用異常來控制程序流”的規則最初來自狹窄得多的上下文,這意味着您通常不應該拋出使用同一方法捕獲的異常,即,將它們用作一種GOTO。 。 但是,就像在這個行業中很常見的那樣,最初的動機已經完全被人們遺忘了,而贊成我只能形容為盲目,鸚鵡時尚,重復。

如果您直接插入用戶名而不進行任何檢查,並且假定數據庫中存在相同的用戶名,那么此時您將得到一個異常,否則它將成功在數據庫中插入記錄。 根據標准編碼慣例(以我的觀點),您應該首先檢查唯一性,如果數據庫中不存在用戶名,則在數據庫中插入記錄。

正確的做法不是您的情況下的異常處理,您應該使用自動遞增的主鍵。

PostgreSQL自動增量

暫無
暫無

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

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