TransactionRequiredException на OptimisticLockException - PullRequest
0 голосов
/ 12 марта 2010

У меня есть следующий класс, который генерирует последовательные номера карт. Я пытаюсь оправиться от 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 голосов
/ 12 марта 2010

Из Javadoc OptimisticLockException:

Бросается провайдером персистентности при возникновении конфликта оптимистической блокировки. Это исключение может быть вызвано как часть вызова API, сброса или во время фиксации. Текущая транзакция, если она активна, будет помечена для отката.

Таким образом, текущая транзакция JTA действительно помечена для отката. Другими словами, если вы хотите «повторить попытку», вам придется начать новую транзакцию (и если вы используете транзакцию, управляемую контейнером, это означает вызов метода, для которого контейнер начнет новую транзакцию).

Я не эксперт по швам, но, тем не менее, я не понимаю:

  • Почему вы передаете EntityManager в качестве параметра? Не вводится EntityManager (используя аннотацию @In в POJO, если я не ошибаюсь). Повторное использование его в рекурсивном вызове звучит неправильно.
  • Где находится транзакционный материал? Разве вы не должны использовать @Transactional(REQUIRED) или что-то подобное (может быть, оно автоматическое)?

ИМХО, первый пункт - большая часть вашей проблемы.

0 голосов
/ 12 марта 2010

Ну ... с чего мне начать?

Если вы просто хотите сгенерировать последовательные числа, что делать с базой данных? Например, используя последовательность или оператор обновления в форме

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

Или, если только один процесс генерирует числа, как насчет синхронизации генератора в Java? В конце концов, увеличение счетчика вряд ли займет достаточно много времени, чтобы считаться узким местом параллелизма.

Далее, ваш генератор не является потокобезопасным, поскольку вы сохраняете изменчивое состояние в переменной экземпляра (количество повторных попыток) без какой-либо синхронизации.

Я не знаю Seam, но если hibernate выдает исключение, сеанс hibernate больше не должен использоваться, и типичным ответом является откат текущей транзакции. Ваш рекурсивный вызов не запускает новую транзакцию, и, очевидно, менеджер сущностей нуждается в ней. Посмотрите, как ваша структура выполняет разграничение транзакций.

...