OptimisticLockException上的TransactionRequiredException

时间:2010-03-11 23:27:56

标签: java hibernate orm jpa seam

我有以下类生成顺序卡号。 我试图通过递归调用相同的方法从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;
}
}

2 个答案:

答案 0 :(得分:0)

嗯......我从哪里开始?

如果您只想生成序列号,那么让数据库做到这一点呢?例如,使用序列,或使用表单

的更新语句
update Card
set cardnumber = cardnumber + 1 where id = ?

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

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

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

答案 1 :(得分:0)

来自OptimisticLockException的javadoc:

  

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

因此,当前的JTA事务确实标记为回滚。换句话说,如果要“再试一次”,则必须启动一个新事务(如果使用容器管理事务,则表示调用容器将启动新事务的方法)。

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

  • 为什么要将EntityManager作为参数传递?不是EntityManager注入(如果我没有错的话,在POJO中使用@In注释)。在递归调用中重用它听起来不对。
  • 交易内容在哪里?你不应该使用@Transactional(REQUIRED)或类似的东西(可能它是自动的)?
恕我直言,第一点是你问题的重要部分。