Почему кэш второго уровня не используется для определенного объекта?

#nhibernate

#nhibernate

Вопрос:

Я запускаю профилировщик NHibernate и не могу понять, почему некоторые объекты извлекаются из кэша второго уровня, а некоторые нет.

Я настроил все необходимые вещи — кэш 2-го уровня включен (SysCache2), и кэширование установлено только для чтения для объектов, которые вызывают у меня проблемы. Я использую транзакции везде.

Во-первых, мои объекты выглядят следующим образом:

 Employee { Id, Name, CurrentOffice }

Office { Id, Name }

Team { Id, Name, Office }
  

Во-вторых, вот несколько примеров из профилировщика NH, чтобы продемонстрировать проблему:

Сессия # 1

Профиль показывает следующий вызов SQL. Это генерируется вызовом Session.Get():

ВЫБЕРИТЕ office_.Идентификатор, office_.Имя ИЗ Office office_, ГДЕ office_.Id = 5

Сессия # 2

В сеансе 2 загружается сотрудник, который затем вызывает запрос на его текущий офис. Кэш второго уровня используется правильно, поскольку office был кэширован в сеансе # 1:

ВЫБЕРИТЕ employee.Идентификатор, employee_.Name, employee_.CurrentOfficeId ИЗ Employee_ ГДЕ employee_.Id = 1

офис загрузки кэша 2-го уровня (5 /* id */)

Сессия # 3

Затем загружаются некоторые команды, которые вызывают нетерпеливый выбор в связанном с ними офисе. Но теперь кэш 2-го уровня не используется для office, который мы должны были кэшировать в предыдущем сеансе.

ВЫБЕРИТЕ team_.Идентификатор, team_.Name , team_.OfficeId ИЗ команды team_ ГДЕ team_.Идентификатор в (7,8,9)

ВЫБЕРИТЕ office_.Идентификатор, office_.Имя ИЗ Office office_, ГДЕ office_.Id = 5

Почему возникает последняя инструкция SQL в сеансе # 3 — почему кэш 2-го уровня не используется, как это было в сеансе # 2?

Комментарии:

1. Можете ли вы также предоставить сопоставления, которые вы используете для своих объектов? Возможно ли, что Office удален из кэша перед вашим третьим сеансом из-за истечения срока действия кэша или из-за нехватки памяти? Также версия NHibernate может быть полезна для воспроизведения проблемы.

2. Привет, спасибо, это запущено на моем локальном компьютере, так что памяти достаточно. Я использую NH 2.1. Срок действия кэша установлен на 20 минут — я проверил это в журналах NHibernate. Сопоставления выполняются с помощью Fluent NHibernate, и в них нет ничего особенного. Сопоставления включают вызовы Cache. Только для чтения или кэш. NonStrictWrite.

Ответ №1:

Я разобрался с этим.

В базе кода выполнялся вызов, который использовал Session.CreateSQLQuery().executeUpdate().

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

Мораль истории, не используйте Session.CreateSQLQuery().executeUpdate() без указания объекта.

Комментарии:

1. Можете ли вы указать объект при использовании executeUpdate()? Насколько я понимаю, вы используете executeUpdate () для пакетов, где вы специально не хотите, чтобы кэш обновлялся. Мне было бы очень интересно посмотреть, как вы поддерживаете постоянство при использовании метода ExecueUpdate().

2. Возможно, вы имеете в виду кэш 1-го уровня. На самом деле я понятия не имею — мой ответ здесь был основан на ограниченном понимании, которое я мог получить от трассировки через исходный код NHibernate с помощью отладчика. Все, что я знаю, это то, что при выполнении запроса весь мой кэш 2-го уровня был уничтожен. Я изменил запрос на выполнение с использованием raw ADO.NET команда, и теперь она ведет себя намного лучше. Я попытаюсь разобраться, что на самом деле происходит, и обновлю свой ответ чем-то более официальным.