哪个更好:捕获数据库异常还是创建手动检查?

时间:2013-08-14 10:19:55

标签: database exception

我正在使用hibernate与MySQL数据库服务器。考虑一个示例数据库表:

create table User (
    USER_ID int not null auto_increment primary key,
    USERNAME varchar(50) not null unique,
    PASSWORD varchar(50) not null
)

使用此表结构时,如果尝试存储更长或重复的用户名,则抛出org.hibernate.exception。 DataException 和org.hibernate.exception。 ConstraintViolationException

问题:在这种情况下,哪种方法更好:

  1. 在传递值之前检查数据库约束(防止预期的异常)。
  2. 稍后传递未经检查的数据并捕获数据库异常(DataException和ConstraintViolationException)。
  3. 由于检查名称长度是一个恒定时间操作,我更喜欢手动检查它,但这个问题对我来说很重要,因为手动确保用户名唯一性要求我迭代一长串现有用户。

    请建议哪种方法更值得推荐。谢谢你的回复!

4 个答案:

答案 0 :(得分:2)

我会两个

你不应该让hibernate异常渗透到持久层之外 - 代码的用户可能根本不知道(也不应该)你的持久性实现使用hibernate,所以抛出一个 excpetion - 一个适合调用者看到它的API。

如果您可以检查代码中输入的有效性,那比让数据库爆炸要好得多。您可以定义并抛出域异常:

if (username.length() > 8) {
    throw new BadUsernameException("username is longer than 8 chars");

你甚至可以找到用户名是否已被使用过:

if (<query database to find username already used>)
    throw new BadUsernameException("username already used");

或者您可以针对每种情况单独抛出异常,但要注意通过异常控制流的反模式。


你仍然需要捕捉由于竞争条件引起的异常,但确实很少见。您可以选择抛出域异常。

答案 1 :(得分:1)

无论如何,你总是要做2)。在任何情况下,您的客户端代码都不能强制执行您可能想要的许多事情(主键,在提交时强制执行的约束等)。只有数据库才能提供正确的一致性检查。

如果你不介意在你的编码(数据库,中间和用户界面)上加倍/加倍,那么肯定做2并做1但是请记住,客户端检查总是会冒很快过时的风险因为它完成了。数据库检查不是这样。

答案 2 :(得分:0)

从用户的角度来看,将填充的表单发送到DB并且仅因为用户名太大而返回异常是不可接受的。在AJAX时代。

所以,有三件事:

  • 用于检查条件的UI,但UI可能无法验证外键
  • 您的domaind / service还应提供验证。假设你上面有REST服务器和UI。您无法确定仅使用正确的UI填充REST以及REST客户端是否验证了大小 - 它可能不会
  • DB必须验证所有约束,并且它主要是唯一可以验证所有条件的地方,例如在外键的情况下。

我相信中间点大多是放松的。

答案 3 :(得分:0)

你应该做到这两点。在向数据库发送查询之前实施简单检查可能会节省您的时间并使您的服务更具响应性。同时,捕获异常会使您的服务远离真正意外的行为,并使其更加用户友好。

您还提到了用户名唯一性。如果您检查代码中是否存在此名称,则应该执行查询并根据结果采取措施 - 空或不。