2008-10-03 59 views
8

这是this question的特定版本。
我想检查我是否插入重复行。我应该以编程方式检查它在我的应用程序层:逻辑:数据库或应用程序/ 2(约束检查)

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

,或者我应该赶在数据库层抛出,引发异常时,我违反了该限制?

try 
{ 
    HibernateSessionFactory.getSession().save(obj); 
} 
catch(ConstraintViolationException e) 
{ 
    throw new DuplicateObjectException(); 
} 

编辑:换句话说:虽然约束是有保留(这是很好的数据库设计,无论如何,我不能肯定我的应用程序将是唯一一个访问表)应我靠在约束条件下处理违规行为将会引发的异常,或者我最好还是检查一下?

EDIT2:当然,我做检查+在事务内插入,锁表,以确保没有其他进程正在写另一个纪录同时

回答

7

首先,您需要必须有一个主键或唯一的限制在数据库以正确执行此唯一性 - 没有问题。

鉴于约束存在,你应该在应用程序代码哪种方式?我喜欢尝试插入并捕获异常。因为大概大多数插入操作都会成功,所以只有少数插入操作会失败,因为重复项(这就是“异常”意味着什么!):在数据库将要执行自己的约束检查时,在每次插入之前执行存在检查效率不高。

而且,它在理论上是可能的存在检查是错误的呢 - 如果有人设法犯了相同键值的记录在小间隔间存在的检查,您的插入。然后,如果你不捕获数据库异常,你会相信插入成功,但实际上并不成功。

1

在一般情况下,我会尽量避免编码依赖错误被抛出是因为我做错了什么。但有时候,这就是你所能做的。在你的情况下,我认为你应该先检查一下。

2

你需要捕捉数据库例外,除非你能保证你的应用程序是有史以来插入行(和以往任何时候都将插入行)到你的数据库的唯一一个。

编辑:我可能误解了这个问题,但我仍然认为选项B(HibernateSessionFactory抛出数据库中的ConstraintException)是更好的选择。另一个应用程序可能会在检查和实际函数调用之间的时间间隔中插入一些东西,这总是有一点小概率。另外,检查重复的唯一方法是执行额外的查询,这只是性能上不必要的消耗。

我的问题的独到理解是,在选择A的欺骗检查将在内部进行(即仅使用该程序已经创建的数据结构,并没有询问,直到INSERT)。我原来的回答是回应这种方法。

1

这将打破(允许重复的条目),如果约束被丢弃由于某种原因(一般维修工作,其中DBA忽略重新启用它)。你应该检查应用程序中的这种情况。

但是,数据库设计的好处是让数据库强制实施约束(正如您已经正确指出的那样),因为其他人也可能正在使用该数据库。作为概括,最好假定应用程序和数据库存在M:M关系 - 几乎所有情况都是如此。

1

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

如果该异常有足够的信息可以产生一个实际上可以帮助用户的错误消息,那么只需捕获异常,分析它,然后继续。

如果该异常没有足够的信息,那么您必须检查错误情况,并向用户产生一个有用的错误消息,说明他们做错了什么。

问题是“异常是多么不透明”之一?有些是非常不透明的。其他人已经足够了,你可以解析消息字符串并找出对用户说的话。

0

一旦hibernate从您的must discard the session会话中抛出异常(请参阅第11.2.3节)。因此,如果您需要检查dups并继续使用相同的会话,那么您别无选择,只能先在应用程序中进行检查。

另外,第一个代码段中的代码有可能会导致另一个进程可能插入一条记录,这会导致在检查重复记录和实际插入时间之间引发重复异常。

2

您检查该对象是否仅存在于应用程序代码中,然后一旦满足它就不会轻易保存该对象。但另一个并发客户端可能会在您的两行代码之间插入自己的对象。所以你会得到一个重复的异常,只是这一次你没有抓住它。

您必须执行save()并捕获异常。否则,与其他并行客户端在同一个数据库上工作的竞争条件。