Кеш в 2-tier приложении
От: MozgC США http://nightcoder.livejournal.com
Дата: 19.04.08 01:38
Оценка:
Здравствуйте,

Есть 2-tier бизнес-приложение:
[ UI + BLL + DAL ] <---> [ Data Storage ]

Что вы думаете о реализации кеша на клиентах? Нужно ли? Какие проблемы при этом возникают и как их можно решить?

Я вот у себя решил сделать кеш клиентов, поставщиков и производителей. Разместить его в DAL. Сделал.
Правда что-то не догадался запрофилировать скорость работы до использования кеша и после, поэтому насколько повысилась производительность на клиентах сказать не могу.

Ну плюсы какие: В памяти только один объект в кеше и все ссылки на него, а не куча одинаковых объектов (например если заказ на 1000 позиций, то в позициях заказа мы не будем иметь 1000 разных объектов производителя которые по сути представляют одного и того же производителя). Ну и из БД не надо тянуть лишний раз объекты которые в кеше. Это особенно полезно в ситуациях типа опять же ситуации с заказом. Читаем заказ из БД и не надо нам читать из БД и создавать на каждую позицию объект производителя — дергаем его из кеша: ManufacturerRepository.GetByID(manufacturerID);

Ну да ладно, это я отвлекся.

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

Начинаются думы и приседания с синхронизацией кеша.
Потом в голову приходит мысль: Может кеш делать только для объектов которые изменяются реально очень редко (раз в несколько дней и реже). Либо например из класса Customer убрать поля Balance и LastOrderN и сделать работу с ними через методы типа CustomerRepository.GetCustomerBalance(Customer customer) и т.д.?

Что скажете?

Буду рад если кто-то внесет ясность в этот вопрос, ну и вообще вашим мнениям
Re: Кеш в 2-tier приложении
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 19.04.08 04:34
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Буду рад если кто-то внесет ясность в этот вопрос, ну и вообще вашим мнениям


Если у вас все изменения проходят через Repository, то он вволне может при изменении объекта сохранять изменения в кеше.
Re: Кеш в 2-tier приложении
От: sch  
Дата: 19.04.08 05:03
Оценка:
MC>Потом в голову приходит мысль: Может кеш делать только для объектов которые изменяются реально очень редко (раз в несколько дней и реже). Либо
Представляете себе, заводят новую запись, а она не появляется на каком-то клиенте... будет очень неприятно.

Я бы что предложил:
1) сделать кеш на сервере,
2) оставить кеш на клиенте, но инвалидировать в нем все данные после каждого цикла работы программы. Например, пользователь редактирует заказ, закончил реактировать -- чистим кеш.

Если сеть у вас быстрая, то будет не на много медленнее, а вот пиротехнических эффектов будет значительно меньше.
Re[2]: Кеш в 2-tier приложении
От: MozgC США http://nightcoder.livejournal.com
Дата: 20.04.08 16:26
Оценка:
G>Если у вас все изменения проходят через Repository, то он вволне может при изменении объекта сохранять изменения в кеше.

А как это поможет в обновлении кеша на других клиентах?

sch>Представляете себе, заводят новую запись, а она не появляется на каком-то клиенте... будет очень неприятно.

Ну.. если другой клиент не найдет что-то в кеше, то кеш автоматом обновится... Проблема в обновлениях. Типа отправили заказ поставщику, его номер последнего заказа в БД и на клиенте, с которого отослали заказ, увеличился на единицу, а другие клиенты в сети об этом не узнают и если с них попытаются следующий заказ этому же поставщику отправить, будет попытка присвоить заказу номер, который уже на самом деле занят предыдущим заказом.

sch>Я бы что предложил:

sch>1) сделать кеш на сервере,
На каком сервере? Я же описал архитектуру... Есть 2 физических слоя, на первом UI/BLL/DAL (клиентские машины), а второй слой — сервер СУБД.

sch>2) оставить кеш на клиенте, но инвалидировать в нем все данные после каждого цикла работы программы. Например, пользователь редактирует заказ, закончил реактировать -- чистим кеш.

Опять же, как это поможет для обновления данных на других клиентах? Ну допустим создали новый заказ поставщику, сохранили, отослали поставщику. Чистим кеш на этом клиенте. ...А мужики то не знают Т.е. остальные то клиенты не узнают что у данного поставщика увеличился номер последнего заказа, и из кеша будут брать старый номер.

sch>Если сеть у вас быстрая, то будет не на много медленнее, а вот пиротехнических эффектов будет значительно меньше.

Сеть быстрая, гигабит, клиентов мало, сеть занята только под работу ПО. Но я не понимаю в каком случае пиротехнических эффектов будет меньше?
Re: Кеш в 2-tier приложении
От: mselez  
Дата: 20.04.08 19:25
Оценка:
Здравствуйте, MozgC, Вы писали:
....
MC>Правда что-то не догадался запрофилировать скорость работы до использования кеша и после, поэтому насколько повысилась производительность на клиентах сказать не могу.

Это наводит на мысль, что вы хотите хорошо работающую систему сделать еще лучше, т.е. оптимизируете без нужды.

MC>Ну плюсы какие: В памяти только один объект в кеше и все ссылки на него, а не куча одинаковых объектов (например если заказ на 1000 позиций, то в позициях заказа мы не будем иметь 1000 разных объектов производителя которые по сути представляют одного и того же производителя).


Странно, что вы это приписываете к плюсам применения кеша. Так должно быть всегда. Разве в базе данных производитель не в одном экземпляре хранится, а все на него только ссылаются? Также и в клиенте должно быть.
Re: Кеш в 2-tier приложении
От: stump http://stump-workshop.blogspot.com/
Дата: 20.04.08 20:27
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте,


MC>Есть 2-tier бизнес-приложение:

MC>[ UI + BLL + DAL ] <---> [ Data Storage ]

MC>Что вы думаете о реализации кеша на клиентах? Нужно ли? Какие проблемы при этом возникают и как их можно решить?


В клиент-серверном приложении функции кэширования полностью лежат на сервере БД, и делает он это весьма эффективно, и к тому же разруливает проблемы с конкурентным доступом. В общем-то помимо просто хранения данных, это и есть основная работа сервера БД.
На клиенте лучше ничего не кэшировать.

MC>Ну плюсы какие: В памяти только один объект в кеше и все ссылки на него, а не куча одинаковых объектов (например если заказ на 1000 позиций, то в позициях заказа мы не будем иметь 1000 разных объектов производителя которые по сути представляют одного и того же производителя). Ну и из БД не надо тянуть лишний раз объекты которые в кеше. Это особенно полезно в ситуациях типа опять же ситуации с заказом. Читаем заказ из БД и не надо нам читать из БД и создавать на каждую позицию объект производителя — дергаем его из кеша: ManufacturerRepository.GetByID(manufacturerID);

Это забота DAL, и это умеют большинство ORM движков. Конечно если в загружаемых данных есть 100 ссылок на один и тот же экземпляр бизнес объекта, то все они должны указывать на один экземпляр объекта. При этом следует использовать паттерн Unit of fWork. Т.е. время этих объектов на клиенте очень мало, оно ограничено одной бизнес транзакцией.

MC>Ну да ладно, это я отвлекся.


MC>Возникли проблемы с синхронизацией кеша на разных клиентах.

MC>Казалось бы такие сущности как клиент, поставщик, производитель редко изменяются.
MC>Но дело в том что у меня например в классе клиента есть поля Balance и LastOrderN, которые могут изменяться несколько раз в день.
MC>Рассинхронизация значений этих полей может привести к очень неприятным последствиям.

MC>Начинаются думы и приседания с синхронизацией кеша.

MC>Потом в голову приходит мысль: Может кеш делать только для объектов которые изменяются реально очень редко (раз в несколько дней и реже). Либо например из класса Customer убрать поля Balance и LastOrderN и сделать работу с ними через методы типа CustomerRepository.GetCustomerBalance(Customer customer) и т.д.?

MC>Что скажете?


Еще раз повторю: На клиенте лучше ничего не кэшировать. Приведенные вами проблемы лишнее тому свидетельство.
Понедельник начинается в субботу
Re[2]: Кеш в 2-tier приложении
От: MozgC США http://nightcoder.livejournal.com
Дата: 20.04.08 22:18
Оценка:
Здравствуйте, mselez, Вы писали:

M>Странно, что вы это приписываете к плюсам применения кеша. Так должно быть всегда. Разве в базе данных производитель не в одном экземпляре хранится, а все на него только ссылаются? Также и в клиенте должно быть.


Как это реализовать без кеша?
Re[2]: Кеш в 2-tier приложении
От: MozgC США http://nightcoder.livejournal.com
Дата: 20.04.08 22:29
Оценка:
Здравствуйте, stump, Вы писали:

S>Конечно если в загружаемых данных есть 100 ссылок на один и тот же экземпляр бизнес объекта, то все они должны указывать на один экземпляр объекта.

Повторю вопрос, заданный мной в предыдущем посте: как это сделать без кеша? Я имею в виду чтобы по всей программе на клиенте было единство экземпляра объекта?

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

Допустим нужно выбрать все заказанные сегодня нашими customer'ами позиции и оформить общий заказ поставщику. Допустим что таких позиций 1000. В каждой позиции есть поле ManufacturerID и допустим, для примера, поле CustomerID (хотя скорее там будет поле OrderID). Нам нужно эти 1000 позиций считать из БД и получить (инстанциировать и заполнить) объекты OrderLine, которые включают в себя поля Manufacturer и опять же, для примера, Customer. Получается, что нам нужно либо джоином тянуть с каждой заказанной позицией еще информацию о производителе и клиенте, чтобы инстанциировать объекты Manufacturer и Customer. И так для каждой позиции, если нет кеша.

Как правильно решить такую задачу без кеша?
Re[3]: Кеш в 2-tier приложении
От: stump http://stump-workshop.blogspot.com/
Дата: 21.04.08 07:50
Оценка:
Здравствуйте, MozgC, Вы писали:

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


S>>Конечно если в загружаемых данных есть 100 ссылок на один и тот же экземпляр бизнес объекта, то все они должны указывать на один экземпляр объекта.

MC>Повторю вопрос, заданный мной в предыдущем посте: как это сделать без кеша? Я имею в виду чтобы по всей программе на клиенте было единство экземпляра объекта?
Да кэш есть, но не "по всей программе на клиенте" а в проеделах бизнес транзакции. Я же давал ссылку на паттерн Unit of Work Фаулера. Посмотрите там же Identity Map
Понедельник начинается в субботу
Re: Кеш в 2-tier приложении
От: Blazkowicz Россия  
Дата: 21.04.08 13:06
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Есть 2-tier бизнес-приложение:

MC>[ UI + BLL + DAL ] <---> [ Data Storage ]
MC>Что вы думаете о реализации кеша на клиентах? Нужно ли? Какие проблемы при этом возникают и как их можно решить?

Вариантов-то не много.
1) Отказатся от подобного кеширования. Реализовать дополнительные выборки. Это все увеличивает число запросов к базе.
2) Сконфигурировать поведение кеша в соответствии с бизнес логикой. Уменьшить время жизни объектов в кеше. Так чтобы снизить вероятность получения из кеша объекта который уже изменился в базе. Классифицировать объекты на те которые
— Никогда не меняются
— Меняются очень редко, так что в течении одной транзакции можно смело пользоватся закешированым экземпляром.
— Меняются часто, так что кешировать нельзя вообще.
3) Реализовать нотификацию изменений. Например регистрировать в базе IP клиентов, рассылать по UDP информацию об обновления.
Re[2]: Кеш в 2-tier приложении
От: MozgC США http://nightcoder.livejournal.com
Дата: 23.04.08 01:49
Оценка:
В общем, очень долго поразмышляв, я решил отказаться от кеша на клиенте.
Точнее использовать только "местный кеш", в пределах одной бизнес-транзакции.

Но сначала решил сделать "замеры" и вот результаты:
Задача: загрузка всех позиций из заказа клиента. Позиций 80, среди 80 позиций 7 разных производителей. ХП к сожалению не использовались в виду лени их создания. ПО и СУБД находились на одном компьютере (1-tier).

Схема 1:
Кеширование "на процесс", т.е. единый кеш на весь клиент и на все время работы клиента. Кеш предварительно заполнен всеми производителями.
Результат: 19 мс

Схема 2:
Местное кеширование, т.е. как я сейчас собираюсь сделать — кеширование в пределах бизнес-транзакции.
Результат: 23 мс

Схема 3:
Местное кеширование. Местный кеш вначале бизнес-транзакции полностью заполняется производителями.
Результат: 12 мс

Схема 4:
Без какого-либо кеширования на клиенте, вся информация о производителях подключаются INNER JOIN'ом и для каждой позиции создается свой объект производителя:
Результат: 11 мс

Схема 5:
Без какого-либо кеширования на клиенте, за каждым производителем лезем отдельным запросом в БД.
Результат: 177 мс

На результаты конечно нельзя сильно полагаться из-за того что не использовались ХП и думаю мог быть достаточный overhead из-за парсинга и построения планов зарпосов СУБД.
Смущает результат первой схемы. Он почему-то больше чем результат схемы 3, хотя казалось бы результаты должны быть одинаковы. Разница только что в схеме 1 использовался мой самодельный Cache<T> который прямо делегировал работу в Dictionary, а в схеме 3 Dictionary использовался напрямую.

Результаты подтвердили мои мысли о том, что использование единого кеша на процесс особых преимуществ по скорости не дает, и что схемы 2-3 дают хорошие результаты при намного меньшем геморое.
Но тут все-таки вопрос к более опытным: какие могут быть подводные камни при использовании кеша на бизнес-транзакцию вместо кеша на процесс? Само собой сразу приходит на ум синхронизация изменений, типа в одном окошечке изменили, в другом окошке изменения отобразились. Но реально ли это нужно и реально ли из-за этого могут быть какие-нибудь проблемы?

Теперь буду думать как красиво сделать использование такого кеша на бизнес-транзакцию. Если делать отдельный generic класс типа LocalCache, то ему видимо надо будет передавать объект доступа к БД из DAL, реализующий какой-нибудь универсальный IAccessor с методом типа LoadObject(PrimaryKey key), либо сразу делегат на метод загрузки объекта по PK. Либо делать отдельные классы кешей на каждую сущность, типа CustomerLocalCache =) но это я почти уверен неправильно. Как лучше? Буду рад примерам.
Re[3]: Кеш в 2-tier приложении
От: Ziaw Россия  
Дата: 23.04.08 07:45
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>В общем, очень долго поразмышляв, я решил отказаться от кеша на клиенте.

MC>Точнее использовать только "местный кеш", в пределах одной бизнес-транзакции.
вот это правильно.

MC>Но сначала решил сделать "замеры" и вот результаты:

MC>Задача: загрузка всех позиций из заказа клиента. Позиций 80, среди 80 позиций 7 разных производителей. ХП к сожалению не использовались в виду лени их создания. ПО и СУБД находились на одном компьютере (1-tier).

от того, что 2 tier'а запущены на одном компьютере они не стали одним tier'ом.

тесты поскипаны, лучший вариант там где кеширование отдано серверу (INNER JOIN) почему-то обойден вниманием.

Я вот не понимаю, зачем изобретать свои "быстрые" велосипеды? Когда есть готовые ORM решения с реализацией unit-of-work и кешированием.
Почему нельзя взять (N)Hibernate и использовать этот самый INNER JOIN? Что такого должен уметь ваш кеш, чего не умеет Hiber?

MC>На результаты конечно нельзя сильно полагаться из-за того что не использовались ХП и думаю мог быть достаточный overhead из-за парсинга и построения планов зарпосов СУБД.

Чтобы об этом не думать — нужно всеголишь прогнать тесты второй раз, сервер должен закешировать запросы и планы. Городить для этого ХП явный overhaed.

ХП почти неизбежное зло в 2-tier. От того что неизбежное злом они быть не перестают и их использование желательно свести к минимуму, логику работы и контракты которого способны удержать в голове все разработчики.
Re[4]: Кеш в 2-tier приложении
От: MozgC США http://nightcoder.livejournal.com
Дата: 23.04.08 21:59
Оценка:
Здравствуйте, Ziaw, Вы писали:

MC>>Задача: загрузка всех позиций из заказа клиента. Позиций 80, среди 80 позиций 7 разных производителей. ХП к сожалению не использовались в виду лени их создания. ПО и СУБД находились на одном компьютере (1-tier).

Z>от того, что 2 tier'а запущены на одном компьютере они не стали одним tier'ом.
Стали. Формально стали, хотя все понимают что в этом случае single-tier и 2-tier идентичны и вся разница просто в расположении СУБД.

Z>тесты поскипаны, лучший вариант там где кеширование отдано серверу (INNER JOIN) почему-то обойден вниманием.

Он обойден вниманием потому что в этом тесте создавалась куча одинаковых объектов, т.е. не было уникальности производителя в пределах транзакции. Надо возможно провести тест когда в БД будет происходить JOIN но при этом на клиенте будет использоваться кеш на транзакцию для обеспечения единства объектов. Но мне в этом варианте не нравится что надо создавать запросы с JOIN'ом, перечислять все поля из нескольких таблиц и создавать их alias'ы, т.к. могут быть совпадения имен полей, типа ID, Name.

Z>Я вот не понимаю, зачем изобретать свои "быстрые" велосипеды? Когда есть готовые ORM решения с реализацией unit-of-work и кешированием.

Z>Почему нельзя взять (N)Hibernate и использовать этот самый INNER JOIN? Что такого должен уметь ваш кеш, чего не умеет Hiber?
Наверное дело в двух вещах:
1) не доверяю ORM в вопросе скорости, хотя конечно сразу говорю что не пробовал даже.
2) банально не доходили руки попробовать и не хочется переделывать какую-никакую имеющуюся архитектуру.
Я думаю эти причины удерживают многих.

MC>>На результаты конечно нельзя сильно полагаться из-за того что не использовались ХП и думаю мог быть достаточный overhead из-за парсинга и построения планов зарпосов СУБД.

Z>Чтобы об этом не думать — нужно всеголишь прогнать тесты второй раз, сервер должен закешировать запросы и планы. Городить для этого ХП явный overhaed.
А ну тогда все ок, тесты прогонял много раз.

Z>ХП почти неизбежное зло в 2-tier. От того что неизбежное злом они быть не перестают и их использование желательно свести к минимуму, логику работы и контракты которого способны удержать в голове все разработчики.

Почему зло то? Наверное мы представляем разные ХП, я представляю совсем небольшие ХП с минимумом логики или ее отсутствием (когда просто один запрос помещается в ХП). Большие ХП на несколько страниц лично мне не нравятся.
Re[5]: Кеш в 2-tier приложении
От: Ziaw Россия  
Дата: 24.04.08 06:01
Оценка:
Здравствуйте, MozgC, Вы писали:

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


MC>>>Задача: загрузка всех позиций из заказа клиента. Позиций 80, среди 80 позиций 7 разных производителей. ХП к сожалению не использовались в виду лени их создания. ПО и СУБД находились на одном компьютере (1-tier).

Z>>от того, что 2 tier'а запущены на одном компьютере они не стали одним tier'ом.
MC>Стали. Формально стали, хотя все понимают что в этом случае single-tier и 2-tier идентичны и вся разница просто в расположении СУБД.
tier != компьютер, для отделения одного tier от другого достаточно того, что для общения они используют межпроцессные коммуникации.

Z>>тесты поскипаны, лучший вариант там где кеширование отдано серверу (INNER JOIN) почему-то обойден вниманием.

MC>Он обойден вниманием потому что в этом тесте создавалась куча одинаковых объектов, т.е. не было уникальности производителя в пределах транзакции. Надо возможно провести тест когда в БД будет происходить JOIN но при этом на клиенте будет использоваться кеш на транзакцию для обеспечения единства объектов. Но мне в этом варианте не нравится что надо создавать запросы с JOIN'ом, перечислять все поля из нескольких таблиц и создавать их alias'ы, т.к. могут быть совпадения имен полей, типа ID, Name.


Z>>Я вот не понимаю, зачем изобретать свои "быстрые" велосипеды? Когда есть готовые ORM решения с реализацией unit-of-work и кешированием.

Z>>Почему нельзя взять (N)Hibernate и использовать этот самый INNER JOIN? Что такого должен уметь ваш кеш, чего не умеет Hiber?
MC>Наверное дело в двух вещах:
MC>1) не доверяю ORM в вопросе скорости, хотя конечно сразу говорю что не пробовал даже.
Не доверяю другим, не смотрел, сам сделаю быстрее и лучше. Чукча не читатель? Зачем делать свой ORM не убедившись в том, что готовые не устривают?
MC>2) банально не доходили руки попробовать и не хочется переделывать какую-никакую имеющуюся архитектуру.
Пока я вижу, только то, что вы хотите многое переделать, только бы не использовать что-то готове.

Z>>ХП почти неизбежное зло в 2-tier. От того что неизбежное злом они быть не перестают и их использование желательно свести к минимуму, логику работы и контракты которого способны удержать в голове все разработчики.

MC>Почему зло то? Наверное мы представляем разные ХП, я представляю совсем небольшие ХП с минимумом логики или ее отсутствием (когда просто один запрос помещается в ХП). Большие ХП на несколько страниц лично мне не нравятся.

Предлагаю закрыть эту тему, она ведет в священные войны
Re[6]: Кеш в 2-tier приложении
От: MozgC США http://nightcoder.livejournal.com
Дата: 24.04.08 10:26
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>tier != компьютер, для отделения одного tier от другого достаточно того, что для общения они используют межпроцессные коммуникации.

Недостаточно =) Но на самом деле это все неважно, бюрократия, формальности

Z>Не доверяю другим, не смотрел, сам сделаю быстрее и лучше. Чукча не читатель? Зачем делать свой ORM не убедившись в том, что готовые не устривают?

Z>Пока я вижу, только то, что вы хотите многое переделать, только бы не использовать что-то готове.
Думаю что постараюсь познакомиться с NHibernate, однако не все так просто, в проекте уже используются сотни запросов и хранимых процедур, сложно это все будет переделывать чтобы ввести использование ORM.

PS.
Кто-нибудь покажет пример как лучше (правильнее) работать с Identity Map в пределах бизнес-транзакции? Как сделать это универсально для повторного использования во всех бизнес-транзакциях? Как в этом случае лучше строить запросы (INNER JOIN или отдельным запросом по ID вытаскивать что нужно если это не находится в кеше)?
Re[7]: Кеш в 2-tier приложении
От: Ziaw Россия  
Дата: 24.04.08 11:59
Оценка:
Здравствуйте, MozgC, Вы писали:

Z>>Не доверяю другим, не смотрел, сам сделаю быстрее и лучше. Чукча не читатель? Зачем делать свой ORM не убедившись в том, что готовые не устривают?

Z>>Пока я вижу, только то, что вы хотите многое переделать, только бы не использовать что-то готове.
MC>Думаю что постараюсь познакомиться с NHibernate, однако не все так просто, в проекте уже используются сотни запросов и хранимых процедур, сложно это все будет переделывать чтобы ввести использование ORM.

Думаю вам будет проще взять чтонибудь полегче NHibernate, хотя и его можно научить маппить результаты SQL запросов. Взгляните на простые датамапперы вроде iBatis или BLToolkit.

MC>PS.

MC>Кто-нибудь покажет пример как лучше (правильнее) работать с Identity Map в пределах бизнес-транзакции? Как сделать это универсально для повторного использования во всех бизнес-транзакциях? Как в этом случае лучше строить запросы (INNER JOIN или отдельным запросом по ID вытаскивать что нужно если это не находится в кеше)?

Для этого нужна как минимум метаинформация о первичном ключе (маппинги), она у вас уже есть или надо прикручивать? Когда мы знаем что является ключем дальнейшие действия тривиальны по сути (добавляем к UnitOfWork IDictionary<Type, IDictionary<Key, object>>) и проверяем на загруженность. Однозначного ответа как лучше строить запросы нет, в некоторых случаях оптимальнее джойн, в некоторых — отдельным запросом.
Re[8]: Кеш в 2-tier приложении
От: MozgC США http://nightcoder.livejournal.com
Дата: 24.04.08 19:52
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Думаю вам будет проще взять чтонибудь полегче NHibernate, хотя и его можно научить маппить результаты SQL запросов. Взгляните на простые датамапперы вроде iBatis или BLToolkit.


А они помогут с темой данного поста — т.е. с тем чтобы не лазить каждый раз в БД (т.е. какой-либо кеш) и с обеспечением единства объектов?

MC>>PS.

MC>>Кто-нибудь покажет пример как лучше (правильнее) работать с Identity Map в пределах бизнес-транзакции? Как сделать это универсально для повторного использования во всех бизнес-транзакциях? Как в этом случае лучше строить запросы (INNER JOIN или отдельным запросом по ID вытаскивать что нужно если это не находится в кеше)?

Z>Для этого нужна как минимум метаинформация о первичном ключе (маппинги), она у вас уже есть или надо прикручивать? Когда мы знаем что является ключем дальнейшие действия тривиальны по сути (добавляем к UnitOfWork IDictionary<Type, IDictionary<Key, object>>) и проверяем на загруженность. Однозначного ответа как лучше строить запросы нет, в некоторых случаях оптимальнее джойн, в некоторых — отдельным запросом.


У меня нет UnitOfWork.
Re[4]: Кеш в 2-tier приложении
От: MozgC США http://nightcoder.livejournal.com
Дата: 25.04.08 00:26
Оценка:
Наваял вот, поругайте немножко?

    public class IdentityMap<T> : IDisposable where T : IIdentifiable
    {
        private readonly IAccessor<T> _accessor;
        private readonly Dictionary<int, T> _cache = new Dictionary<int, T>();

        public IdentityMap(IAccessor<T> accessor)
        {
            _accessor = accessor;
        }

        public T GetByID(int id)
        {
            if (!_cache.ContainsKey(id))
                Add(_accessor.GetByID(id));
            return _cache[id];
        }

        public void Add(T item)
        {
            if (!_cache.ContainsKey(item.ID))
                _cache.Add(item.ID, item);
        }

        public void Dispose()
        {
            _cache.Clear();
        }
    }


Использую так:

    private IList<OrderLine> GetOrderLines(int orderID)
    {
        IList<OrderLine> orderLines = new List<OrderLine>();
        using (DbManager db = new DbManager())
        {
            using (IDataReader reader = db.ExecuteReader(
                string.Format("SELECT * FROM order_lines WHERE OrderID = {0}", orderID)))
            {
                using (IdentityMap<Manufacturer> map = new IdentityMap<Manufacturer>(new ManufacturerAccessor()))
                {
                    while (reader.Read())
                    {
                        int manufacturerID = Convert.ToInt32(reader["ManufacturerID"]);
                        Manufacturer manufacturer = map.GetByID(manufacturerID);
                        OrderLine line = CreateOrderLine(reader, manufacturer);
                        orderLines.Add(line);
                    }
                }
            }
        }
    }


Что скажете?
Re[5]: Кеш в 2-tier приложении
От: GlebZ Россия  
Дата: 25.04.08 07:18
Оценка: 1 (1)
Здравствуйте, MozgC, Вы писали:

MC>Что скажете?

1. В принципе Indentity Map задумывался как единый на транзакцию. И его основная цель отнюдь не кэширование, а обеспечение согласованности данных. То есть, если параллельная транзакция меняет данный бизнес-объект, мы в данной транзакции имеем актуальную версию объекта. Свойство кэшируемости здесь вторично. В твоей версии ты можешь просто поднять список объектов который будет храниться в течении всей транзакции. Это будет аналогично твоему коду и наверное поудобнее.

2. Тут не стоит забывать некоторую вещь которая присуща всем кэшам и ORM (за исключения кэша БД). Удерживая кэш в памяти, мы не можем делать аггрегирующие запросы в БД, так как актуальной версии там еще нет. Это всегда нужно учитывать.
... << RSDN@Home 1.2.0 alpha rev. 789>>
Re[9]: Кеш в 2-tier приложении
От: Ziaw Россия  
Дата: 25.04.08 08:40
Оценка:
Здравствуйте, MozgC, Вы писали:

Z>>Думаю вам будет проще взять чтонибудь полегче NHibernate, хотя и его можно научить маппить результаты SQL запросов. Взгляните на простые датамапперы вроде iBatis или BLToolkit.

MC>А они помогут с темой данного поста — т.е. с тем чтобы не лазить каждый раз в БД (т.е. какой-либо кеш) и с обеспечением единства объектов?
iBatis поможет, BLToolkit сами смотрите, вообще, разобраться с примерами и сделать тесты у вас займет часа 2 на обе либы.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.