我有以下类生成顺序卡号。 我试图通过递归调用相同的方法从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;
}
}
答案 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)
或类似的东西(可能它是自动的)?