4

我正在将休眠与 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)。

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

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

4

4 回答 4

3

我会做这两个

你不应该让休眠异常从持久层中渗透出来——你的代码的用户可能不知道(他们也不应该)你的持久实现使用休眠,所以抛出一个异常——一个适合 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");

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


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

于 2013-08-14T10:38:00.447 回答
1

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

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

于 2013-08-14T10:24:57.953 回答
0

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

所以,有三件事:

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

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

于 2013-08-14T10:38:23.303 回答
0

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

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

于 2013-08-14T12:39:31.273 回答