NHibernate кэш первого уровня
От: DK-Warder  
Дата: 11.02.09 07:30
Оценка:
Добрый день. Возможно задаю глупый вопрос, но поиски в интернете так и не дали мне подходящий ответ.
Собственно проблема такая. Запускаем два клиентских приложения, оба они при запуске вычитывают список Entity (некоторая сущность). Далее меняем в одном приложении имя у сущности и сохраняем в базу. Если после этого во втором приложении нажать кнопочку обновить, то ничего не изменится, имя у сущности останется старым. А вот если в первом приложении добавить новую сущность, то при обновлении во втором приложении она появится.
Хочется чтобы при обновлении получались актуальные данные из базы. Можно перед обновлением делать Clear у ISession или создавать другую ISession, либо вообще использовать IStatelessSession, но подходящие ли это решения, не приведут ли они к другим проблемам, что посоветуете делать?

Вот например таким тестом можно выразить проблему (тест не срабатывает):
[Test]
public void Cache()
{
    Entity entity = SaveInDBEntityWithName("Имя");

    ISession session1 = OpenNewSession();
    session1.Get<Entity>(entity.Id);

    ISession session2 = OpenNewSession();
    session2.Get<Entity>(entity.Id).Name= "Измененное имя";
    session2.Flush();

    Assert.AreEqual("Измененное имя, session1.Get<Entity>(entity.Id). Name);
}
Re: NHibernate кэш первого уровня
От: Ziaw Россия  
Дата: 11.02.09 09:02
Оценка:
Здравствуйте, DK-Warder, Вы писали:

DW>Хочется чтобы при обновлении получались актуальные данные из базы. Можно перед обновлением делать Clear у ISession или создавать другую ISession, либо вообще использовать IStatelessSession, но подходящие ли это решения, не приведут ли они к другим проблемам, что посоветуете делать?


В случае когда базу правят несколько приложений — следует использовать короткоживущие сессии (одна сессия на одну транзакцию БД) либо stateless сессии.
... << RSDN@Home 1.2.0 alpha 4 rev. 0>>
Re[2]: NHibernate кэш первого уровня
От: DK-Warder  
Дата: 11.02.09 10:46
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, DK-Warder, Вы писали:


DW>>Хочется чтобы при обновлении получались актуальные данные из базы. Можно перед обновлением делать Clear у ISession или создавать другую ISession, либо вообще использовать IStatelessSession, но подходящие ли это решения, не приведут ли они к другим проблемам, что посоветуете делать?


Z>В случае когда базу правят несколько приложений — следует использовать короткоживущие сессии (одна сессия на одну транзакцию БД) либо stateless сессии.


Спасибо, так и попробую.
Re: NHibernate кэш первого уровня
От: meowth  
Дата: 11.02.09 15:37
Оценка:
Здравствуйте, DK-Warder, Вы писали:

DW>Добрый день. Возможно задаю глупый вопрос, но поиски в интернете так и не дали мне подходящий ответ.

DW>Собственно проблема такая. Запускаем два клиентских приложения, оба они при запуске вычитывают список Entity (некоторая сущность). Далее меняем в одном приложении имя у сущности и сохраняем в базу. Если после этого во втором приложении нажать кнопочку обновить, то ничего не изменится, имя у сущности останется старым. А вот если в первом приложении добавить новую сущность, то при обновлении во втором приложении она появится.
DW>Хочется чтобы при обновлении получались актуальные данные из базы. Можно перед обновлением делать Clear у ISession или создавать другую ISession, либо вообще использовать IStatelessSession, но подходящие ли это решения, не приведут ли они к другим проблемам, что посоветуете делать?

DW>Вот например таким тестом можно выразить проблему (тест не срабатывает):

DW>
DW>[Test]
DW>public void Cache()
DW>{
DW>    Entity entity = SaveInDBEntityWithName("Имя");

DW>    ISession session1 = OpenNewSession();
DW>    session1.Get<Entity>(entity.Id);

DW>    ISession session2 = OpenNewSession();
DW>    session2.Get<Entity>(entity.Id).Name= "Измененное имя";
DW>    session2.Flush();

DW>    Assert.AreEqual("Измененное имя, session1.Get<Entity>(entity.Id). Name);
DW>}
DW>


Это нормальное поведение — NHibernate может отследить изменения только в направление код->БД, а не наоборот.

Вывод:
— не бойтесь создавать и убивать сессии — сами по себе они достаточно легковесны;
— не используйте одну сессию для нескольких транзакций в конкуррентной среде (когда могут существовать одновременно несколько сессий).

Еще одно маленькое замечание: для NHibernate версии > 2.0 всегда используйте явные транзакции в коде, даже на чтение.

Как-то так.
Re[2]: NHibernate кэш первого уровня
От: Ахмед  
Дата: 12.02.09 03:27
Оценка: +1
Здравствуйте, meowth, Вы писали:

M>Еще одно маленькое замечание: для NHibernate версии > 2.0 всегда используйте явные транзакции в коде, даже на чтение.


Интересно, можно узнать — почему?
Re[3]: NHibernate кэш первого уровня
От: meowth  
Дата: 12.02.09 11:56
Оценка: 9 (2)
Здравствуйте, Ахмед, Вы писали:

А>Здравствуйте, meowth, Вы писали:


M>>Еще одно маленькое замечание: для NHibernate версии > 2.0 всегда используйте явные транзакции в коде, даже на чтение.


А>Интересно, можно узнать — почему?


Можно
Формальный ответ — потому что так сказали разработчики =)

Фактический — по следующим соображениям:
а) При некоторых конфигурациях версионирования данных (имеется в виду модель оптимистических блокировок) будут некорректно работать версии.
б) Ручное управление транзакциями — это зло, и обычно от него отказываются в пользу автоматического/декларативного управления — TransactionScope, например (лично я использую Spring.Transactions). В момент перехода вы будете очень удивлены результатом, когда все начнет работать по-другому, потому что менеджер транзакций теперь явно рулит транзакциями сессии Хибернейта :D
в) Чтение данных вне явной транзакции НЕ использует кэш второго уровня. Нет, это сейчас вы его не включили, а потом подключите и будете долго ломать голову, почему он не работает, и переписывать каждое обращение к ISession.
г) Такой способ вынуждает писать правильно: делать выборку внутри сессии (транзакции) и сразу диспозить ее — в противном случае вы нахватаете косяков при обновлении коллекций и lazy-load'е.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.