Найти или вставить на основе уникального ключа с помощью Hibernate

Я пытаюсь написать метод, который вернет объект Hibernate на основе уникального, но не основной ключ. Если объект уже существует в базе данных, я хочу вернуть его, но если это не так ' • Я хочу создать новый экземпляр и сохранить его перед возвратом.

ОБНОВЛЕНИЕ: Позвольте мне пояснить, что приложение, для которого я пишу это, в основном является пакетным обработчиком входных файлов. Системе необходимо читать файл построчно и вставлять записи в базу данных. Формат файла в основном представляет собой денормализованное представление нескольких таблиц в нашей схеме, поэтому мне нужно проанализировать родительскую запись, либо вставить ее в базу данных, чтобы я мог получить новый синтетический ключ, либо, если он уже существует, выберите его. Затем я могу добавить дополнительные связанные записи в другие таблицы, которые имеют внешние ключи обратно к этой записи.

Причина, по которой это становится сложным, заключается в том, что каждый файл должен быть либо полностью импортирован, либо не импортирован вообще, то есть все вставки и обновления, сделанные для данный файл должен быть частью одной транзакции. Это достаточно просто, если есть s только один процесс, который выполняет весь импорт, но я хотел бы, если возможно, разбить его на несколько серверов. Из-за этих ограничений мне нужно иметь возможность оставаться внутри одной транзакции, но обрабатывать исключения, когда запись уже существует.

Сопоставленный класс для родительских записей выглядит следующим образом:

@Entity
public class Foo {
    @Id
    @GeneratedValue(strategy = IDENTITY)
    private int id;
    @Column(unique = true)
    private String name;
    ...
}

Моя первая попытка написать этот метод - следующим образом:

public Foo findOrCreate(String name) {
    Foo foo = new Foo();
    foo.setName(name);
    try {
        session.save(foo)
    } catch(ConstraintViolationException e) {
        foo = session.createCriteria(Foo.class).add(eq("name", name)).uniqueResult();
    }
    return foo;
}

Проблема в том, что когда имя, которое я ищу, существует, при вызове uniqueResult () генерируется исключение org.hibernate.AssertionFailure. Полная трассировка стека приведена ниже:

org.hibernate.AssertionFailure: null id in com.searchdex.linktracer.domain.LinkingPage entry (don't flush the Session after an exception occurs)
    at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:82) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:190) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:147) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1185) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1709) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
    at org.hibernate.impl.CriteriaImpl.uniqueResult(CriteriaImpl.java:369) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]

Кто-нибудь знает, что вызывает это исключение? Поддерживает ли спящий режим лучший способ достижения этой цели?

Позвольте мне также предупредительно объяснить, почему я сначала вставляю, а затем выбираю, если и когда это не удается. Это должно работать в распределенной среде, чтобы я мог ' t синхронизируйте проверку, чтобы увидеть, существует ли уже запись и вставка. Самый простой способ сделать это - позволить базе данных обрабатывать эту синхронизацию, проверяя нарушение ограничений при каждой вставке.

19
задан Vlad Mihalcea 3 November 2017 в 13:23
поделиться