2016-01-06 2 views
0

У меня есть система, основанная на спящем режиме 4. У меня есть ограничение уникальности в таблице и необходимо обработать его следующий образом:зимуют 4 ручки уникального индекса исключение

try{ 
    getMyService().create(myobj); 
}catch(PersistenceException p){ 
    //constraint fails 
    myobj.setConstraintColumn("new non unique value"); 
    getMyService().create(myobj);//should save it 
} 

, к сожалению, я не могу изменить дизайн системы, поэтому мне нужно просто разобраться в этом.

EDIT

я получаю следующее исключение:

org.hibernate.AssertionFailure: null id in entry (don't flush the Session after an exception occurs) 

Код создания метода:

public E create(E entity) { 
     entityManager.persist(entity); 
     entityManager.flush(); 
     entityManager.refresh(entity); 
     return entity; 
} 
+0

Я не уверен, какой у вас конкретный вопрос. Вы говорите, что предпочли бы, чтобы система присваивала уникальное значение, но вынуждены поймать ConstraintViolation, когда это произойдет. В этот момент вы готовы присвоить новое значение и повторите попытку. Что вы пробовали и какие у вас проблемы? –

+0

Извините, я только что редактировал свое сообщение. Спасибо – avalon

ответ

0

Я, наконец, выяснил проблему. Итак, позвольте мне объяснить один за другим. Прежде всего, посмотрите на

Propagation.REQUIRES_NEW does not create a new transaction in Spring with JPA

Тогда, например, у нас есть класс и метод, как:

public class MyClass{ 
    @Transactional 
    public void myMethod(){ 
     .... 
    } 

} 

Итак, в первую очередь, позволяет считать, что MyMethod находится в своем собственном транзакция полностью, потому что транзакции основаны на AOP, и они будут выполняться, когда соответствующий аспект будет срабатывать, но только после завершения метода, исключения исключений и т. д. Таким образом, мы не можем частично совершать, частично откатываться, откатывать не полностью и т. д. Таким образом, мы должны сделать следующее:

  1. Начало большой внешняя транзакция
  2. Начать новую вложенную транзакцию, попробуйте вставить запись.
  3. Если вложенная транзакция не удалась, она будет отброшена назад, но внешний будет работать.
  4. Если первая вложенная транзакция завершилась неудачно, запустите новую вложенную транзакцию и вставьте запись с новыми данными, что предотвратит выброс ConstaintViolationException.

Таким образом, в этом случае, мы создаем класс:

public class ServiceHelper{ 
    @Transational(proparation = **Propagation.REQUIRED_NEW**) 
    public void tryConstraint throws MyConstraintException{ 
     try{ 
      //insert 
     }catch(ConstraintViolationException e){ 
      throw new MyConstraintException(e); 
     }catch(Exception ex){ 
      throw new Exception(ex); 
     } 
    } 

    @Transational(proparation = **Propagation.REQUIRED_NEW**) 
    public void insertWithNoConflict throws Exception { 
     //Set new data 
     //insert, if still CVE or anything other, just throw it , or leave it for unchecked exceptions then 
    } 


} 

И наш сервис:

public class MyService{ 
@Autowired 
private ServiceHelper serviceHelper; 

@Transactional(propagation = **Propagation.REGUIRED_NEW**) 
public void createWithCheck(){ 
    try{ 
     serviceHelper.tryConstraint(); 
    }catch(MyConstraintException e){ 
     serviceHelper.insertWithNoConflict(); 
    } 
} 
} 

Но есть еще странная ситуация, потому что мне нужно использовать методы MYSERVICE для создание записей в ServiceHelper, но я не могу их получить там, потому что это вызовет круговые инъекции, поэтому я должен получить их через сервисные фабрики, например:

MyService service = (MyService)ServicesFactory.getInstance().getBean(MyService.BEAN_ID) 

И мне это не нравится. Но этот подход работает, я проверил его сегодня.

Мы должны знать 2 вещи: прежде всего мы ничего не можем сделать с транзакцией внутри метода, мы не можем начинать там никаких новых транзакций и т. Д. Контекст транзакции имеет отношение к методу полностью, он все равно будет быть там до окончания метода. И второе: required_new не работает, когда мы запускаем метод из метода того же самого прокси-класса.

1

Не ясно, где ваши границы транзакционные. Если вы выбрали исключение, вам необходимо будет: 1) Убедитесь, что первая транзакция закрыта (она должна быть, но не уверена - см., Если вы пытаетесь выполнить только вложенную транзакцию # 2) 2) начать новую транзакцию прежде чем вы сможете снова и снова удержаться/скрыться (и впоследствии зафиксировать это).

+0

Почему первая транзакция должна быть закрыта? Что делать, если я хочу подавить это исключение? Почему нет? – avalon

+0

Насколько я понимаю, когда генерируется исключение (уникальное ограничение будет выдавать исключение, которое вы не можете контролировать или подавлять), транзакция недействительна. В этом состоянии у вас нет другого выбора, кроме как начать все заново. –

+0

Спасибо, но я поймал это исключение, не понимаю, как это признается недействительным. – avalon

Смежные вопросы