0

我知道应该使用数据库序列来获取表中下一个键的值(让我们假设一个单列数字主键),但是如果不使用序列,你是否看到任何明显的代码气味以下代码(JPA 的代码是 Java,但该模式实际上是独立于语言和技术的):

  boolean haveSucceeded = false;
  int _i = 0 ;
  while ((!haveSucceeded) && (_i++ < MAX_RETRIES)) {
     try {
          user.setId(getFacade().maxId()+1); // line A
          getFacade().create(user);          // line B
          haveSucceeded = true;
     } catch (javax.ejb.EJBTransactionRolledbackException exc) {
          debug("ConstraintValidationException, "+ ( (_i<MAX_RETRIES)?"retrying":"giving up"));
     }
  }

由于并发访问(也可能来自其他应用程序实例)而发生重试以解决可能的冲突,并且因为不能保证行 A(计算最大值的位置)和行 B(插入行的位置)将对相同的数据进行操作。

4

2 回答 2

2

这看起来不是线程安全的。您应该以线程安全的方式:

  • 锁定用户表
  • 读取当前的 max(id)
  • 添加 1 并将其用作下一个 id
  • 解锁桌子

这近似于使用自动增量在数据库中发生的情况。

如果您无法锁定表,请同步该方法,无论是制作它static synchronized还是使用static锁定对象,例如:

 private static final Object lock = new Object();

 void yourMethod() {
     synchronized (lock) {
         // your code here
     }
 }

如果您有多个服务器实例正在运行,那么这种方法是不够的。

于 2012-08-21T19:48:04.603 回答
-1

如果您费心尝试通过重试访问,为什么不在使用接口“Connection”.createStatement() 将语句创建为 CONCUR_READ_ONLY 或 CONCUR_UPDATABLE 时设置“方法”。大多数情况下,数据库本身控制读取并发,但连接可以作为查询的一部分告诉数据库如何读取它。我不明白,当访问问题异常发生“如果有过”的可能性比读取并发的任何问题更多时,为什么还要为循环而烦恼。Niether 我能理解为什么如果你正在创建一个用户,你为什么要如此不区分数据值,你应该首先检查用户是否存在,然后中止这个过程并将一条消息发回给打算的新用户“选择另一个用户名“ ETC..

于 2012-08-21T20:07:14.170 回答