В новом Hibernate Session, созданном в событии, не видна сущность, сохраненная в другом сеансе (но в одной транзакции) - PullRequest
2 голосов
/ 24 марта 2011

Я использую PreInsertEventListener Hibernate для аудита полей моей таблицы.Я также использую Spring для создания своих SessionFactory и TransactionManager.

Некоторые другие подробности, которые могут иметь отношение:
Используется OpenSessionInViewFilter
Версия Hibernate: 3.5.1-Final
Версия Spring: 3.0.3.RELEASE
База данных Oracle 10g

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

public boolean onPreInsert(final PreInsertEvent event) {
    final SessionFactory factory = triggeringSession.getSessionFactory();
    Session triggeringSession = event.getSession();
    triggeringSession.doWork(new Work() {
        public void execute(Connection connection) throws SQLException {
            Session newSession = factory.openSession(connection);
            saveStuff(newSession);
            newSession.flush();
        }
    });
    return false;
}

В моемsaveStuff метод Мне нужно сохранить новую сущность.

private void saveStuff(Session session) {
   HistoricReference historicReference = new HistoricReference();
   historicReference.setId("12345"); // This is actually an unique ID based on a generated auditing number and table that was inserted into

    // If this haven't been created I want it to be saved
    if (session.get(HistoricReference.class, "12345") == null) {
        session.save(historicReference);
    }

    // Other stuff saved (regarding old/new values etc.) that historicReference as id (as part of composite id)

}

Моя проблема в том, что если я вставлю 2 новых сущности одного типа в одну транзакцию, я получу уникальное нарушение ограничения в таблице HistoricReference.Я отлаживал, и код, который проверяет, создан ли он уже, всегда возвращает false, но в конце, когда транзакция фиксируется, он пытается вставить ее дважды.Это потому, что каждый раз создается новый сеанс?

Пример:

MyEntity entity1 = new MyEntity();
MyEntity entity2 = new MyEntity();  
session.save(entity1);
session.save(entity2);

Я получу уникальную ошибку ограничения в конце запроса (при попытке зафиксировать).Это потому, что когда onPreInsert(...) вызывается для entity2, он снова вызывает session.save(historicReference).Если я не сохраню entity2, проблем не возникнет.

Будет ли session.get(HistoricReference.class, "12345") возвращать значение, даже если оно было сохранено в другом сеансе, но в той же незафиксированной транзакции?

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

Любая помощь будет оценена.

Ответы [ 2 ]

1 голос
/ 25 марта 2011

Пожалуйста, используйте session.merge() вместо session.save() вот отличное объяснение, почему .

Надежда, которая помогает.

0 голосов
/ 24 марта 2011

Одним из решений является перемещение сохранения HistoricReference во FlushEvent.В событии preInsert просто получите данные и соберите их в локальной карте / списке потока, а затем получите доступ и сохраните их в FlushEvent.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...