逻辑:数据库还是应用程序/2(约束检查)

9

这是一个关于此问题的具体版本。
我想要检查是否正在插入重复的行。我应该在我的应用程序层面进行编程检查吗?

if (exists(obj))
{
    throw new DuplicateObjectException();
}
HibernateSessionFactory.getSession().save(obj);

或者我应该捕获由数据库层抛出并在违反约束时触发的异常?
try
{
    HibernateSessionFactory.getSession().save(obj);
}
catch(ConstraintViolationException e)
{
    throw new DuplicateObjectException();
}

编辑:换句话说:虽然限制条件必须保留(这是良好的数据库设计,而且我不能确定我的应用程序将是访问表的唯一方式),我应该依赖于限制条件并处理违规时引发的异常,还是我最好仍要进行检查?

编辑2:当然,在事务内检查+插入,锁定表以确保没有其他进程同时写入另一条记录。

7个回答

8
首先,你必须在数据库上拥有主键或唯一约束来正确实施这种唯一性 - 这是毋庸置疑的。
既然有了约束,那么在应用程序中应该如何编码呢?我更喜欢尝试插入并捕获异常。因为大多数情况下插入将成功,只有少数情况下会出现重复(这就是“异常”的含义!):在数据库将执行自己的约束检查时,在每次插入之前执行exists检查是低效的。
此外,存在检查在理论上可能是错误的 - 如果其他人设法在存在检查和插入之间的短时间内提交具有相同键值的记录。 然后,如果不捕获数据库异常,您将认为插入成功,而实际上并非如此。

2
除非你能保证你的应用程序是唯一一个插入行(并且将来也只会插入行)到你的数据库中的,否则你需要捕获数据库异常。
编辑:我可能误解了问题,但我仍然认为选项B(HibernateSessionFactory从数据库中抛出ConstraintException)是更好的选择。总有一小部分可能性是另一个应用程序在你的检查和实际函数调用之间插入了一些内容。此外,检查重复项的唯一方法是执行额外的查询,这只会浪费性能。
我最初对问题的理解是,在选项A中,重复项检查将在内部执行(即仅使用程序已经创建的数据结构,并且在INSERT之前不进行任何查询)。我的最初答案是针对这种方法的。

2

在应用程序代码中,您需要检查对象是否存在,确定不存在后再保存该对象。但是,在您的两行代码之间的瞬间,另一个并发客户端可能会插入他们自己的对象。因此,您仍然会得到重复异常,只是这一次您没有捕获它。

您必须执行save()并捕获异常。否则,您将与其他并发客户端竞争同一个数据库。


1
通常情况下,我会尽量避免编写依赖于错误被抛出的代码,因为这意味着我犯了错误。但有时候,这似乎是唯一的解决办法。在你的情况下,我认为你应该先进行检查。

1

如果由于某些原因(通常是DBA忘记重新启用它的维护工作),约束条件被删除,这将导致程序出现错误(允许重复条目)。您应该在应用程序中检查此情况。

然而,良好的数据库设计应该让数据库强制执行约束条件(正如您所指出的那样),因为其他人也可能使用数据库。一般来说,最好假设应用程序和数据库之间存在M:M关系 - 几乎所有情况都是如此。


1

Hibernate(或任何ORM组件)抛出的异常往往很难解释。

如果异常提供了足够的信息,您可以生成一个真正有用的错误消息并捕获异常,然后进行分析并继续下一步操作。

如果异常没有足够的信息,则必须检查错误条件,并向用户提供有用的错误消息,告诉他们正在做错误的事情。

问题是“异常有多难以理解”?有些异常非常难懂,而其他异常提供了足够的信息,使您能够解析消息字符串并找出对用户说什么。


0

一旦Hibernate从会话中抛出异常,您必须丢弃该会话(请参见第11.2.3节)。因此,如果您需要检查重复项并继续使用同一会话,则除了首先在应用程序中进行检查外别无选择。

此外,在第一个片段中的代码存在这样一种可能性,即另一个进程可能会插入一条记录,导致在您检查重复记录和实际插入之间抛出重复异常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接