1

假设我有一个以 user_id 作为主键的映射用户对象,以及一个具有唯一约束的邮件列。我希望我的程序仅在用户表不存在时才将用户对象保存到用户表中。

我可以在我的插入函数中执行以下操作:

  1. 开始交易
  2. 使用给定邮件查询用户
  3. 如果它不存在,创建一个新用户并使用会话保存它
  4. 如果失败则提交或回滚

有两个问题:

  1. 执行两个查询很昂贵。如果我使用纯 SQL,我可能会使用“INSERT IGNORE”语法,但在我的情况下,我想使用休眠保存方法,并且我想最后保存用户对象。有解决办法吗?
  2. 并发。我的应用程序的两个实例是否有可能同时运行。两者都将使用具有相同“mail”参数的“addUser”函​​数。第一个将经历第 2 阶段,并且找不到使用该邮件的用户。第二个也将通过第 2 阶段而没有找到用户,因为第一个实例仍然没有保存他的用户并提交。然后第一个实例将保存并提交用户,然后第二个实例将保存并提交用户,该用户与第一个实例的邮件具有相同的邮件。当然它会失败,因为约束。我错过了什么吗?

如果我是对的,我应该怎么做:

  1. 希望它不会发生。
  2. 在事务开始时锁定用户表以进行读写。
  3. 将 try...except 添加到函数中,这将排除唯一约束异常,如果抛出异常,将仅根据其邮件从数据库中选择用户。
  4. 其他解决方案...
4

3 回答 3

1

你几乎总是有可能出现这样的情况,除非你引入了太多的锁定,你的系统变得无法使用。除非您知道这是一个问题,否则您应该只专注于优雅地处理违反唯一约束的问题。

于 2009-02-25T20:16:55.097 回答
0

您应该只专注于优雅地处理唯一约束违规。

您可以通过捕获将被抛出的 ConstraintViolationException 来做到这一点。如果您想要更细化,如果可能会发生多个约束破坏,您可以执行以下操作:

...
} catch (ConstraintViolationException e) {
    if (e.getConstraintName() != null && e.getConstraintName().toLowerCase().equals("the_name_of_your_contraint")) {
        // do something, like add an error to be displayed on the UI
    }
}
于 2009-02-26T01:11:28.900 回答
0

现在我可以做到的独特方式是:

<sql-insert check="none" callable="true">
            {call saveOrUpdate (?, ?, ?, ?, ?)}
 </sql-insert>

http://forum.springsource.org/showthread.php?65265-Hibernate-insert-problem

我无法使其工作的其他选项:

也许您可以使用@SQLInsert Hibernate 注释进行“插入不存在的位置”

下一个选项仅适用于编辑实例:

另一种选择是使用“带有版本列的乐观锁定”并在并发异常的情况下处理异常。

链接:http ://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html#transactions-optimistic

于 2011-09-22T10:11:26.693 回答