【问题标题】:Logic: Database or Application/2 (constraints check)逻辑:数据库或应用程序/2(约束检查)
【发布时间】:2010-09-15 02:14:53
【问题描述】:

这是this question 的特定版本。
我想检查我是否插入了重复的行。我应该在我的应用程序层中以编程方式检查它吗:

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

或者我应该捕获数据库层抛出的异常并在我违反约束时触发?

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

编辑: 换句话说:虽然约束仍然存在(无论如何这是很好的数据库设计,我不能确定我的应用程序将是唯一访问表的应用程序)我应该依赖约束并处理其违规将引发的异常,还是我最好还是检查一下?

EDIT2:我当然会在事务中进行检查+插入,锁定表以确保同时没有其他进程正在写入另一条记录

【问题讨论】:

    标签: database business-logic-layer


    【解决方案1】:

    首先,您必须在数据库上有一个主键或唯一性约束,以正确地执行此唯一性 - 毫无疑问。

    鉴于存在约束,您应该以哪种方式在应用程序中编写代码?我的偏好是尝试插入并捕获异常。因为可能大多数插入都会成功,只有少数会因为重复而失败(这就是“异常”的含义!):在每次插入之前执行存在检查是低效的,因为无论如何数据库都将执行自己的约束检查。

    此外,理论上存在检查仍然可能是错误的 - 如果其他人设法在您的存在检查和插入之间的小间隔内提交具有相同键值的记录。那么,如果你不捕获数据库异常,你会相信插入成功,而实际上它没有。

    【讨论】:

      【解决方案2】:

      您检查该对象是否仅存在于应用程序代码中,然后一旦确定它不存在,就愉快地保存该对象。但是另一个并发客户端可能会在您的两行代码之间插入他们自己的对象。所以无论如何你都会得到一个 Duplicate 异常,只是这次你没有捕捉到它。

      您必须执行 save() 并捕获异常。否则,您将与其他在同一数据库上工作的并发客户端发生争用情况。

      【讨论】:

        【解决方案3】:

        您需要捕获数据库异常,除非您可以保证您的应用程序是唯一向数据库插入行(并且永远将插入行)的应用程序。

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

        我对这个问题的最初理解是,在选项 A 中,重复检查将在内部执行(即仅使用程序已经创建的数据结构,并且在插入之前不进行查询)。我原来的回答是针对这种方法的。

        【讨论】:

          【解决方案4】:

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

          【讨论】:

            【解决方案5】:

            如果由于某种原因(通常是 DBA 忽略重新启用它的维护工作)删除了约束,这将中断(允许重复条目)。您应该在应用程序中检查这种情况。

            但是,让数据库强制执行约束是一种很好的数据库设计(正如您非常正确地指出的那样),因为其他人也可能正在使用该数据库。作为概括,最好假设应用程序和数据库存在 M:M 关系 - 几乎所有时间都是这种情况。

            【讨论】:

              【解决方案6】:

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

              如果异常有足够的信息,您可以生成一条真正帮助用户的错误消息,那么只需捕获异常,分析它,然后继续。

              如果异常没有足够的信息,那么您必须检查错误条件,并向用户提供有用的错误消息,说明他们做错了什么。

              问题是“异常有多不透明”?有些非常不透明。其他人有足够的能力来解析消息字符串并弄清楚要对用户说什么。

              【讨论】:

                【解决方案7】:

                一旦休眠从你must discard the session 的会话中抛出异常(参见第 11.2.3 节)。因此,如果您需要检查重复数据并继续使用同一会话,那么您别无选择,只能先在应用程序中检查。

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2013-04-12
                  • 2023-03-26
                  • 2015-11-08
                  • 2022-11-05
                  • 2011-03-02
                  • 1970-01-01
                  • 2012-03-21
                  • 2013-10-03
                  相关资源
                  最近更新 更多