哪个更好 – 抛出exception或事先检查错误
在连接到postgresql的服务器中,我应该通过执行"select * ..."
检查表中是否已存在用户名,然后获取结果集中的行数,并且i的行数等于零,然后插入用户名?
或者只是在表格中插入用户名。 如果它已经存在,那么它将抛出一个错误,然后可以捕获它。
注意:用户名是主键
做以上哪两项更好?
您应该执行“try-and-catchexception”方法,因为您无论如何都必须这样做。
如果你先检查,没有什么可以阻止有人在你的支票和你的插入之间为该用户插入一行,在这种情况下,即使你的支票没有找到,用户也会在表中。
没有能够在某种事务中运行检查和插入(以便其他人无法在此期间插入该用户)。 你无法确定非例外是否有效。
尽管许多DBMS都提供了事务支持,但我不知道是否会锁定你尚未插入的行:-)
当然,如果您的应用程序设计为只有您的进程将插入用户(并序列化),您可以使用check-first方法。 但是我会发表大量评论,如果你扩大规模,就需要重新审视。
通常的共识是仅对例外情况使用例外而不是作为控制流构造。 在我看来,尝试使用恰好采用的用户名应该被认为是有效的,而不是那种不常见的用例。
换句话说,我会首先检查现有的用户名。
正如@paxdiablo指出的那样,如果您处于multithreading环境中,例如Web服务器,那么您需要添加一些锁定方案或者使用try / catch方法(考虑到两个线程可能竞争添加相同的用户名) )。 然而, 这种情况可以被认为是一种例外情况。
相关问题 (所有结论相同,不对非特殊情况使用例外):
- exception错误是否真的例外?
- C ++:在非特殊情况下是否有理由使用exception
- Juding是否exception是例外
- 为什么使用exception而不是if … else
在这种情况下,答案都不是 。 既不会引发错误,也不会事先检查。 好吧,无论如何。
它可以更简单地处理 – 同时更安全,更快捷:
INSERT INTO users(username, col1) SELECT 'max', 'val1' WHERE NOT EXISTS (SELECT * FROM users WHERE username = 'max')
这将仅在新用户不存在时插入。 PostgreSQL会将命令状态设置为0 rows affected
或0 rows affected
1 row affected
,具体取决于它是否已存在。 无论哪种方式,它都会在此声明后出现。
如果你想要回答:
INSERT INTO users(username, col1) SELECT 'max', 'val1' WHERE NOT EXISTS (SELECT * FROM users WHERE username = 'max') RETURNING username;
仅当用户名尚不存在时,才会返回该用户名。
但是,该操作不是primefaces操作,因此如果您有很多并发,请在表上获取锁定,如下所示:
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;
请注意,这仍然可能失败,即使非常不可能 – 例如,如果另一个事务锁定表并由于某些错误而永远阻止您。
所以,诚然,你仍然需要代码来处理错误情况。 除非您的数据库或应用程序出现问题,否则它永远不会发生。
- 汤姆里对此事。
- 关于锁的手册。
我会说在这种情况下捕获exception是滥用exception概念,如果你之前可以检查它,你应该检查它。
永远不应该使用exception来控制程序的流程。 如果不是例外情况,最好避免例外。
我希望通过查询检查用户是否存在而不是使用exception。 “用户存在”错误的逻辑很快就会成为业务规则。 (你可以在SQL中编写这样的规则,但那是完全不同的世界)
或者只是在表格中插入用户名。 如果它已经存在,那么它将抛出一个错误,然后可以捕获它
问题是有许多其他原因导致例外。 无论如何你必须处理它们。
您将获得许多答案,其中包括“永远不应该使用exception来控制程序的流程”和“exception不适用于控制流程”。 确实,你已经有几个。 你可能像我一样,发现这些陈述完全没有意义。 exception确实控制程序的流程,并且当API被设计为抛出exception时,您没有任何选择,只能相应地使用它。 EOFException
就是一个例子。 当调用抛出它的方法时,您没有任何其他方法来检测EOS。
在这种情况下,适用不同的原则。 如果你测试然后设置,你将引入一个时间窗口,在此期间后续的设置可能会失败,如果set操作可以抛出exception,你必须为它编码。 在这些情况下,您应该只进行设置并相应地处理exception。 这样你的操作是primefaces的,你不必两次编写相同的代码。 一般来说,检测资源是否可用的最可靠方法是尝试使用它(考虑连接到网络服务器),并且检测操作是否会失败的最可靠方法是实际尝试它(考虑这种情况,即将值插入数据结构中,在该数据结构中它是唯一键。
关于“exception永远不应该用来控制程序流程”的规则最初来自一个更窄的上下文,这意味着你通常不应该抛出你在同一个方法中捕获的exception,即将它们用作一种GOTO 。 然而,正如在这个行业中非常普遍的那样,最初的动机完全被遗忘了,我只能将其描述为无意识的,鹦鹉式的,重复的。
如果您直接插入用户名而不进行任何检查,并假设数据库中存在相同的用户名,那么您将获得exception,否则它将在数据库中成功插入记录。 根据标准编码实践(在我看来),您应首先检查唯一性,如果数据库中不存在用户名,则在数据库中插入记录。
正确的做法不是关于你的情况下的exception处理,你应该使用自动递增的主键。
PostgreSQL自动增量
- 我应该声明从方法签名中的方法抛出的所有exception还是仅仅exception的超类?
- JVM如何保证finally块的执行?
- @ControllerAdviceexception处理程序方法未被调用
- 如何处理从C ++通过SWIG到Java的exception
- java:无法重新抛出exception:未处理的exception类型exception
- 将generics用于exception是否明智?
- 如何在解析CSV行中的空位置时避免触发ArrayIndexOutOfBoundsException?
- @ControllerAdvice优于@ExceptionHandler或HandlerExceptionResolver处理exception的优点是什么?
- Java编译器抱怨未报告的IOException