2015-05-05 3 views
0

Я работаю над проектом, где я использую главным образом EJB и JPA, но у меня проблема с ConstraintViolationException, которого не должно было случиться.JPA пакетная вставка, вызывающая ConstraintViolationException

Прежде всего у меня есть MyEntity класс с @Id и несколькими уникальными полями. У меня есть @Stateless MyEntityRepository класс с методом find(), который просто возвращает MyEntity (или null), вызывая метод EntityManager get(). Другого @Stateless боба SaveEntityBean:

@Stateless 
public class SaveEntityBean { 

    @Inject 
    EntityManager em; 
    @Inject 
    MyEntityRepository repository; 

    public void saveEntity(MyEntity me) { 
     if(repository.find(me) == null) { 
      //the place with ConstraintViolationException 
      em.persist(me); 
     } 
    } 
    public void saveEntities(List<...> entities) { 
     for(MyEntity me: entities) 
      saveEntity(e); 
    } 
} 

и метод saveEntities(List<...> entities) вызываются из другого боба:

@Stateless 
@Startup 
public class SaveEntityBean { 

    @Inject 
    SaveEntityBean saveBean; 
    //... 

    @Schedule(hour = "*", minute = "*", second="*/5") 
    @AccessTimeout(unit = TimeUnit.MINUTES, value = 1) 
    public void mainLogicMethod() { 
     List<MyEntity> entities = io.calculateAndGetEntities(); 
     saveBean.saveEntities(entities); 
    } 
} 

где метод io.calculateAndGetEntities() является продолжительной работой IO. Проблема в том, что иногда я получаю org.hibernate.exception.ConstraintViolationException, который, на мой взгляд, не должен происходить, потому что я проверяю состояние MyEntityRepository.find(me) != null перед вызовом метода persist(). Единственная идея, которая у меня есть, заключается в том, что между коммитами существует некоторая задержка, поэтому после вызова метода MyEntityRepository.find(me) в состоянии проверки происходит коммит, и сразу после этого метод persist() выдает исключение.

Пожалуйста, дайте мне какие-либо предложения, что читать и учиться, и как решить проблему.

Редактировать: Я обнаружил, что это проблема с поточной обработкой, поэтому, вероятно, решение имеет блокировку записи/чтения.

+1

Действительно, это похоже на проблему синхронизации - вы выполняете операцию check-then-act в saveEntity(), а таймер mainLogicMethod() создает нити. –

+0

Я перестала читать, когда спотыкалась о переменной me и em в том же объеме. –

ответ

0

Хорошо, как правило, в высокой параллельной среде очень сложно решить эту проблему, и просто блокировка не будет работать (и вы не хотите использовать блокировки таблиц). Сейчас я использую Hibernate @SQLInsert аннотацию из org.hibernate.annotations.SQLInsert так что моя сущность выглядит следующим образом:

@SQLInsert(sql = "INSERT INTO my_entity_table(a, b, c) VALUES(?, ?, ?) ON DUPLICATE KEY UPDATE a=a;") 
public class MyEntity implements Serializable {...} 

Конечно, это будет проблематично, когда Вы хотели бы показать какое-то сообщение об ошибке для пользователя, но в моем случае это хорошо достаточно. Насколько я знаю, этот оператор SQL поддерживается только в MySQL, в других СУБД вы должны использовать разные aproach.

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