Почему iBATIS дает устаревшие результаты, даже если кэширование отключено?


У меня есть веб-приложение, которое я медленно мигрировал с iBATIS 2 на JPA с данными Spring.

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

Например, у меня есть раздел "билет", который показывает список открытых билетов и позволяет просматривать определенные билеты на отдельных сайтах. страницы. Когда я создаю новый билет, я могу правильно просмотреть его на определенной странице. Однако в списке открытых билетов этот новый билет появится только через некоторое время.

Вещи, которые я пытался исключить:

  • я вижу эту проблему даже в системе с отключенным кэшем запросов MySQL
  • я вижу эту проблему, даже когда устанавливаю cacheModelsEnabled="false" в конфигурации iBATIS.
  • я вижу эту проблему даже тогда, когда я полностью удаляю элемент <cacheModel> и атрибуты cacheModel="x" из моей sqlMap файл.
  • как только я перезапускаю приложение, я вижу последние результаты.
  • Когда я выполняю запрос iBATIS должен быть запущен здесь в клиенте MySQL, я делаю вижу новый билет, который отсутствует в результатах iBATIS.
  • Когда я издевался над простым списком билетов, используя Spring MVC и Spring Data JPA, я действительно вижу новый билет.

Я также пытался исключить какое-то странное состояние транзакции с iBATIS, но похоже, что нет транзакция здесь вообще используется.

Что я упускаю? Есть ли что-то еще, что я должен попытаться выяснить? Или, может быть, мне просто следует полностью заменить слой iBATIS на Spring Data JPA, который, похоже, не подвержен этой проблеме?

Обновить

Теперь я прошел через множество моих недавних изменений с git bisect, и я сузил его до изменения, которое ввело весенние org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.

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

2 8

2 ответа:

Если вы делаете select, insert, select в том же SqlSession, тогда кэш SqlSession вызывает эту проблему. Вам нужно будет очистите кэш вручную после вставки: sqlSession.команды clearcache().

Итак, похоже, что здесь произошло сочетание вещей:

    Большая часть моего кода явно не использовала транзакции.
  1. я в какой-то момент изменил использование пула соединений JDBC Tomcat, который не сбрасывает autocommit по умолчанию, когда соединение возвращается в пул. Хотя я ожидаю, что мои старые материалы на основе DBCP делали это неявно.
  2. введение OpenEntityManagerInViewFilter, возможно, вызвало вызов SET autocommit=0 в какой-то момент, без соответствующего SET autocommit=1 позже, если ничего не изменилось.
  3. Случайно или, возможно, по какой-то задумке, код, который вставлял новую запись в базу данных, а затем немедленно извлекал и показывал ее, казалось, получал другой Connection, чем код, который показывал мой список записей.
  4. уровень изоляции транзакций MySQL по умолчанию REPEATABLE-READ означал, что мои списки показывали старые результаты.

Исправление, которое я нашел, которое, кажется, работает в моем тестировании до сих пор, состоит в том, чтобы добавить эти defaultAutoCommit и jdbcInterceptors атрибуты конфигурации моего пула соединений:

<Resource name="jdbc/DB" auth="Container" type="javax.sql.DataSource"
    factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
    ...
    defaultAutoCommit="true" jdbcInterceptors="ConnectionState;StatementFinalizer" />