2016-10-18 15 views
1

Я пытаюсь сохранить много записей в одной транзакции, используя JPA (EclipseLink). Запись имеет первичный ключ, определенный в БД.Множественное нарушение ограничений на флеш и сохранение в одной транзакции

У меня есть несколько дубликатов в фиде, поэтому я знаю, что будет нарушение ограничений. Я хочу поймать исключение ограничения ограничений для одного элемента и продолжать сохранять другие.

Вот мой код:

Entity:

@Entity 
@Table(name="TEST") 
public class TestEntity { 

    @Id 
    private String name; 

    public TestEntity() { 

    } 

    public TestEntity(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 
} 

Операция:

@Transactional 
public void test() { 

    List<String> list = Arrays.asList("A", "B","C","D","D","E","F","G");//duplicated D 

    for(String name: list) { 
     try { 
      TestEntity entity = new TestEntity(name); 
      logger.info("" + entity); 
      entityManager.persist(entity); 
      logger.info("Persist done"); 
      entityManager.flush(); 
      logger.info("Flush done"); 
     } catch(RuntimeException e) { 
      logger.warn("Entry {} was skipped due to following exception {}.", name, e.getLocalizedMessage()); 
     } 
    } 

    logger.info("Importing dictionary finished. "); 
} 

В результате я получаю ограничение нарушение прав для второго D (это то, что я ожидал), но Я получаю это исключение для следующих предметов, и это то, чего я не понимаю.

Я получаю: Внутренняя Exception: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: ограничение уникальности (BBHDEV4.SYS_C0023890) нарушается

Что является причиной этой проблемы?

+0

Вы должны удалить '@ Transactional'. Это гарантирует, что либо все будет сохранено, либо никаких изменений не будет сделано. – coladict

ответ

2

Ваш менеджер организация поддерживает государство, состоящее из все объекты managed (т. е. контекст постоянства) и транзакционное состояние его объектов.

Итак, после того, как флеш запускает нарушение ограничения, объект D по-прежнему управляется и находится в состоянии устаревания и снова будет краснеет в следующем явном флеш-вызове (вы не должны явно вызывать сброс) или в конце текущего сделка. вам необходимо вручную вычеркнуть объект D из контекста персистентности (detach()), прежде чем возобновлять цикл.

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

Сделка - это единое целое, если вы не будете независимы от своих различных операций, вы должны выполнить их в разных транзакциях. Обычно область управления сущностью такая же, как и транзакция (по крайней мере, когда управляется контейнером, то есть с помощью приложения @PersitenceContext), и вы сразу решите обе проблемы.

2

Проблема заключается в том, что вторая D еще часть одной и ту же транзакции/Unit of Work, поэтому на следующую итерации, спящий режим пытается сохранить его снова.

Чтобы исправить это (используя ванильный JPA), вы можете

  • Создать новую транзакцию за единицу, которую нужно обновить.
  • Сделайте обновление с JPA update statement.

С зимуют у вас есть 3-й вариант, который заключается в использовании сессионного, но я не знаю, если EclipseLink имеет понятие лица без EntityManager

+0

Есть ли способ удалить этот объект из текущей транзакции? –

+1

не из текущей транзакции, а из текущего состояния ЭМ: 'detach()' (называемый сеансом спящего режима 'evict'in) – Gab

+0

Что сказал Габл :) - Просто имейте в виду, что это не стандартный вызов JPA, а часть внутренний API EclipseLink. – Augusto

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

  • Нет связанных вопросов^_^