Ручной откат транзакций в шве - PullRequest
6 голосов
/ 07 марта 2012

Эта проблема аналогична Принудительный откат транзакции при ошибке проверки Сценарий таков: пользователь редактирует страницу, транзакция имеет значение MANUAL, поэтому только если мы вызовем flush, она будет зафиксированав базу данных.Теперь пользователь хочет отменить изменения.Все просто, пока вы не сбросили его.

Теперь рассмотрим следующий сценарий: пользователь редактирует страницу с большим количеством AJAX.Некоторые из этих обратных вызовов ajax требуют запросов к базе данных (например, с использованием поля предложений richFaces и т. Д.).Некоторая проверка также выполняется, что требует поиска в базе данных.Проблема в том, что Hibernate автоматически выдаст сброс при выполнении запроса.Таким образом, пользователь не нажимает кнопку сохранения (что приведет к сбросу транзакции), он нажимает кнопку отмены.Что вы делаете сейчас?

Если вы ничего не делаете, изменения будут записаны в базу данных, а не то, что ожидает пользователь.

Вы можете вызвать исключение, помеченное

@ApplicationException(rollback=true)

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

<exception class="com.mycomp.BookingCancelException">
    <end-conversation before-redirect="true"/>  
    <redirect view-id="/secure/Bookings.xhtml">
        <message severity="INFO">#{messages['cancel.rollback']}</message>
    </redirect>
</exception>

в pages.xml, поэтому разговор должен закончиться до того, как мы сделаем перенаправление.Новый разговор должен начаться (с новой транзакции), но, похоже, это происходит не во всех случаях?Почему?

Я читал где-то еще, что вы можете просто использовать

Transaction.instance().rollback();

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

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

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

Обновление 2 : Конечно, откат транзакций не будет работать, если у вас есть страница, где вы используете ajax для обновления значений.Каждая транзакция покрывает только один запрос.Так, например, если вы выполнили, например, 5 изменений с помощью запроса ajax, откат транзакции откатит только изменения с последнего запроса ajax, а не с предыдущих 4-х.

Таким образом, решение действительно заключается в использовании режима сброса MANUAL..

Есть несколько вещей, которые вызовут сброс, даже если вы укажете MANUAL.

  • запрос в запросе ajax может вызвать сброс - используйте setFlushMode (FlushMode.COMMIT)в запросе, чтобы избежать этого.
  • Сохранение сущности может вызвать сброс в зависимости от используемой генерации идентификатора (например, если вы используете стратегию IDENTITY).Вы можете обойти это с помощью каскадов.Если во время редактирования вам нужно создать объекты, которые не имеют никаких реальных связей с основным объектом, который вы редактируете, просто добавьте их в список и сохраните все объекты в этом списке при сохранении.
  • Когдавы запускаете вложенный диалог, или другой бин присоединяется к диалогу, режим сброса которого в этом сеансе устанавливается обратно в AUTO, если вы не укажете @Begin (join = true, flushMode = FlushModeType.MANUAL)

Возможно, вы захотите указать MANUAL в качестве режима по умолчанию в компонентах. Xml

<core:manager concurrent-request-timeout="10000"
  conversation-id-parameter="cid" conversation-timeout="600000" default-flush-mode="MANUAL"/>

Ответы [ 3 ]

0 голосов
/ 11 марта 2012

Может быть полезно знать, что вы можете указать компонентам проверки ajax не flush, используя атрибут bypassUpdates. Вот статья , объясняющая это.

0 голосов
/ 12 декабря 2012

Вы можете управлять своей транзакцией и управлять ею с активированной кнопкой.

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response, String butonPressed)
            throws ServletException, IOException {

        try {
            // Begin unit of work
            HibernateUtil.getSessionFactory()
                    .getCurrentSession().beginTransaction();

        } catch (Exception ex) {
            HibernateUtil.getSessionFactory()
                    .getCurrentSession().getTransaction().rollback();
            throw new ServletException(ex);
        }
        finally
        {
            if ("SAVE".equals(butonPressed))
            {

            // Process request and render page...

            // End unit of work
            HibernateUtil.getSessionFactory()
                    .getCurrentSession().getTransaction().commit();
            }
            else
            {
                HibernateUtil.getSessionFactory()
                        .getCurrentSession().getTransaction().rollback();
            }
        }

    }
0 голосов
/ 10 марта 2012

Вы пробовали

@Begin(flushMode=MANUAL)
someRandomValidationMethodHere(){ ... }

или настройка

<core:manager conversation-timeout="120000" default-flush-mode="manual" />

в компонентах.xml?

...