【问题标题】:Which is better: Catching database exception or creating manual check?哪个更好:捕获数据库异常或创建手动检查?
【发布时间】:2013-08-16 05:59:37
【问题描述】:

我在 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)。

由于检查名称长度是一个常数时间操作,我更喜欢手动检查它,但这个问题对我来说很重要,因为手动确保用户名的唯一性需要我迭代一长串现有用户。

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

【问题讨论】:

  • 预先检查很昂贵(额外查询)并且不可靠(在您检查后,另一个进程可能会添加用户)。编写昂贵的不可靠代码没有多大意义。
  • 请注意,在进程#1 和#2 之间,其他用户可以插入相同的用户名。在某些情况下,检查 #1 可能没有用。但是现在有了强大的 UI,我经常在编写表单时看到错误消息更新。 (例如:写入用户名但未提交后,UI 会告诉我该名称是否被占用)。
  • 所以我可以得出结论,应该手动实现线程安全检查(如检查用户名长度),并捕获 DB 服务器抛出的异常,而确切的结果可能取决于并行线程。?

标签: database exception


【解决方案1】:

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

因此,如果您不介意将您的编码(数据库、中间件和 UI)加倍/加倍,请务必执行 2 和 1,但请记住,客户端检查将始终面临尽快过时的风险因为它已经完成了。数据库检查并非如此。

【讨论】:

    【解决方案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");
    

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


    由于竞争条件,您仍然需要捕获异常,但它们确实很少见。您可以选择引发域异常。

    【讨论】:

      【解决方案3】:

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

      所以,有三件事:

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-11-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多