【问题标题】:TransactionRequiredException on OptimisticLockExceptionOptimisticLockException 上的 TransactionRequiredException
【发布时间】:2010-03-11 23:27:56
【问题描述】:

我有以下生成顺序卡号的类。 我试图通过递归调用相同的方法从 OptimisticLockException 中恢复。但是,我得到了 TransactionRequiredException。在我的情况下,有谁知道如何从 OptimisticLockException 中恢复?

提前非常感谢

@Name("simpleAutoIncrementGenerator")
public class SimpleAutoIncrementGenerator extends CardNumberGenerator{
private static final long serialVersionUID = 2869548248468809665L;

private int numberOfRetries = 0;

@Override
public String generateNextNumber(CardInstance cardInstance, EntityManager entityManager) {

    try{ 
        EntityCard card = (EntityCard)entityManager.find(EntityCard.class, cardInstance.getId());

        if(card != null){

            String nextNumber = "";

            String currentNumber = card.getCurrentCardNumber();

            if(currentNumber != null && !currentNumber.isEmpty()){

                Long numberToInc =  Long.parseLong(currentNumber);
                numberToInc ++;
                nextNumber = String.valueOf(numberToInc);
                card.setCurrentCardNumber(nextNumber);

                                    // this is just to cause a OptimisticLock Exception
                try {
                    Thread.sleep(4000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                entityManager.persist(card);
                entityManager.flush();

                return nextNumber;
            }
        }

    }catch (OptimisticLockException oLE) {

        System.out.println("\n\n\n\n OptimisticLockException \n\n\n\n");
        if(numberOfRetries < CentralizedConfig.CARD_NUMBER_GENERATOR_MAX_TRIES){
            numberOfRetries ++;
            return generateNextNumber(cardInstance,entityManager);
        }

    }catch (TransactionRequiredException trE) {
        System.out.println("\n\n\n\n TransactionRequiredException \n\n\n\n");
        if(numberOfRetries < CentralizedConfig.CARD_NUMBER_GENERATOR_MAX_TRIES){
            numberOfRetries ++;
            return generateNextNumber(cardInstance,entityManager);
        }
    }catch (StaleObjectStateException e) {
        System.out.println("\n\n\n\n StaleObjectStateException \n\n\n\n");
        if(numberOfRetries < CentralizedConfig.CARD_NUMBER_GENERATOR_MAX_TRIES){
            numberOfRetries ++;
            return generateNextNumber(cardInstance,entityManager);
        }
    }

    return null;
}
}

【问题讨论】:

    标签: java hibernate orm jpa seam


    【解决方案1】:

    嗯...我从哪里开始?

    如果你只是想生成序列号,让数据库来做呢?例如使用序列,或使用形式的更新语句

    update Card
    set cardnumber = cardnumber + 1 where id = ?
    

    或者,如果只有一个进程生成数字,那么在 Java 中同步生成器呢?毕竟,增加一个计数器几乎不会花费足够长的时间来成为并发瓶颈。

    接下来,您的生成器不是线程安全的,因为您在没有任何同步的情况下将可变状态保存在实例变量(重试次数)中。

    我不知道Seam,但是如果hibernate抛出异常,应该不再使用hibernate session,典型的响应是回滚当前事务。您的递归调用不会启动新事务,显然实体管理器需要一个。查看您的框架如何进行事务划分。

    【讨论】:

      【解决方案2】:

      来自OptimisticLockException的javadoc:

      在发生乐观锁定冲突时由持久性提供程序抛出。此异常可能作为 API 调用、刷新或提交时的一部分抛出。当前事务,如果一个是活动的,将被标记为回滚。

      所以当前的 JTA 事务确实被标记为回滚。换句话说,如果你想“再试一次”,你将不得不开始一个新的事务(如果你使用的是容器管理的事务,这意味着调用一个容器将启动一个新事务的方法)。

      我不是 Seam 专家,但我仍然不明白:

      • 为什么要传递EntityManager 作为参数? EntityManager 不是注入(如果我没记错的话,在 POJO 中使用 @In 注释)。在递归调用中重复使用它听起来不对。
      • 事务性材料在哪里?你不应该使用@Transactional(REQUIRED) 或类似的东西(也许它是自动的)?

      恕我直言,第一点是您问题的很大一部分。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-15
        • 1970-01-01
        • 2016-11-12
        • 1970-01-01
        • 2013-08-13
        • 1970-01-01
        • 2019-11-01
        • 2020-01-28
        相关资源
        最近更新 更多