транзакционность в business logic comenents
От: AlSer Беларусь  
Дата: 01.06.10 23:15
Оценка:
Доброго времени суток

Как правильно реализовать понятие транзакций на уровне Business Logic Layer,
ведь работа с базами данных должна осуществляеться в Data Access Layer.
Например, компонент из BLL получает данные в виде business entities (или data transfer objects) из таблицы Table1 посредством компонента DAL, обрабатывает их и в результате обработки должен сохранить обработанные business entities обратно в Table1, а также в Table2 (в зависимости от условий еще и в Table3, Table4). И это все должно осуществиться как одна транзакция, т.е. если что-нибудь произойдет во время этой операции (какой-нибудь Exception), то первоначально извлеченные данные должны остаться такими как и были).
Но... ведь BLL не контролирует транзакции (это все в ведении DAL). Как быть?
Какие особенности использования ORM (NHibernate, EF) в этом случае?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: транзакционность в business logic comenents
От: MozgC США http://nightcoder.livejournal.com
Дата: 01.06.10 23:29
Оценка: 3 (2)
Я использую класс TransactionScope в бизнес-слое, типа такого:

public static void Save(Customer customer)
{
    ...
    using (var transactionScope = new TransactionScope())
    {
        // Далее идут вызовы в DAL
        CustomerAccessor.Insert(customer);
        CountryShipmentTermsSet shipmentTermsSet = ShipmentTermsService.GetCountryShipmentTerms(customer.CountryID);
        CustshipmentsAccessor.SaveCustomerShipmentPrices(
            customer.ID,
            shipmentTermsSet.DefaultShipmentTerms.PhysicalWeightPrice,
            shipmentTermsSet.EuropeShipmentTerms.PhysicalWeightPrice,
            shipmentTermsSet.ContainerShipmentTerms.PhysicalWeightPrice);

        transactionScope.Complete();
    }
    ...
}

Все отлично работает.
Re[2]: транзакционность в business logic comenents
От: Sinix  
Дата: 01.06.10 23:57
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Все отлично работает.

До того момента, как требуется DTC, но на машинах клиентов он отключен. Нафиг-нафиг
Re: транзакционность в business logic comenents
От: IT Россия linq2db.com
Дата: 02.06.10 00:19
Оценка:
Здравствуйте, AlSer, Вы писали:

AS>Но... ведь BLL не контролирует транзакции (это все в ведении DAL). Как быть?


Это кто такое сказал?
Если нам не помогут, то мы тоже никого не пощадим.
Re: транзакционность в business logic comenents
От: Gridmer Россия www.i-tt.ru
Дата: 02.06.10 06:21
Оценка: 2 (1) +1
Это известный паттерн "Unit of Work".

Описание с design-pattern.ru:

Обслуживает набор объектов, изменяемых в бизнес-транзакции (бизнес-действии) и управляет записью изменений и разрешением проблем конкуренции данных.

Когда необходимо писать и читать из БД, важно следить за тем, что вы изменили и если не изменили — не записывать данные в БД. Также необходимо вставлять данные о новых объектах и удалять данные о старых.

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

Реализация паттерна Unit of Work следит за всеми действиями приложения, которые могут изменить БД в рамках одного бизнес-действия. Когда бизнес-действие завершается, Unit of Work выявляет все изменения и вносит их в БД.

Как применять см. здесь
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Re[3]: транзакционность в business logic comenents
От: TK Лес кывт.рф
Дата: 02.06.10 07:01
Оценка: 1 (1)
Здравствуйте, Sinix, Вы писали:

S>До того момента, как требуется DTC, но на машинах клиентов он отключен. Нафиг-нафиг


Требование использовать DTC определяется разработчиком. Можно не использовать TransactionScope, а передавать транзакцию явно. В этом случае, вероятность того, что "неожиданно потребуется DTC" уменьшается еще сильнее.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[4]: транзакционность в business logic comenents
От: Sinix  
Дата: 02.06.10 08:09
Оценка:
Здравствуйте, TK, Вы писали:

TK>Требование использовать DTC определяется разработчиком. Можно не использовать TransactionScope, а передавать транзакцию явно. В этом случае, вероятность того, что "неожиданно потребуется DTC" уменьшается еще сильнее.


Дело не в TransactionScope, а в том, что в одной транзакции окажется больше одного durable (или promotable) ресурса. В идеале транзакция должна обрамлять только внесение изменений в СУБД и рулить ей должен DAL (с опциональной возможностью явно указать транзакцию).
Re[2]: транзакционность в business logic comenents
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 02.06.10 08:09
Оценка: +1
Здравствуйте, MozgC, Вы писали:

MC>Я использую класс TransactionScope в бизнес-слое, типа такого:


MC>
public static void Save(Customer customer)
MC>{
MC>    ...
MC>    using (var transactionScope = new TransactionScope())
MC>    {
MC>        // Далее идут вызовы в DAL
MC>        CustomerAccessor.Insert(customer);
MC>        CountryShipmentTermsSet shipmentTermsSet = ShipmentTermsService.GetCountryShipmentTerms(customer.CountryID);
MC>        CustshipmentsAccessor.SaveCustomerShipmentPrices(
MC>            customer.ID,
MC>            shipmentTermsSet.DefaultShipmentTerms.PhysicalWeightPrice,
MC>            shipmentTermsSet.EuropeShipmentTerms.PhysicalWeightPrice,
MC>            shipmentTermsSet.ContainerShipmentTerms.PhysicalWeightPrice);

MC>        transactionScope.Complete();
MC>    }
MC>    ...
MC>}

MC>Все отлично работает.

А если внутри метода Save, кроме CustomerAccessor будет обращение к другому Accessor, который также внутри себя создает соединение, то о-умалчанию включится DTC, который по-умолчанию на клиентских машинах отключен.
Re[5]: транзакционность в business logic comenents
От: Ziaw Россия  
Дата: 02.06.10 08:15
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Дело не в TransactionScope, а в том, что в одной транзакции окажется больше одного durable (или promotable) ресурса. В идеале транзакция должна обрамлять только внесение изменений в СУБД и рулить ей должен DAL (с опциональной возможностью явно указать транзакцию).


Рулить транзакцией, должен BLL, транзакция это часть бизнес логики. Один из вариантов реализации — протаскивание скоупа через thread context.

DAL (в общем случае) не имеет информации о том, когда требуется начать транзакцию, а когда ее завершить.
Re[6]: транзакционность в business logic comenents
От: Sinix  
Дата: 02.06.10 08:28
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Рулить транзакцией, должен BLL, транзакция это часть бизнес логики.

Какой транзакцией? Если у нас первая часть UoW (с извращённой точки зрения это просто генерация скрипта обновления) — нам ничего не нужно от ACID. Если вторая — атомарное внесение изменений — то это проблемы DAL, BLL максимум может явно потребовать (или запретить) целостность данных и явно указать scope для распределённых транзакций (вообще-то распределённость также должна инкапсулироваться DALом).

Z>Один из вариантов реализации — протаскивание скоупа через thread context.

Вы который скоп имеете в виду? [ThreadStatic] переиспользуется потоками в пуле. У CallContext тоже есть свои нюансы
Автор: Sinix
Дата: 18.04.10
. Повторяю — проблема не в scope,а в наличии нескольких durable ресурсов.

Z>DAL (в общем случае) не имеет информации о том, когда требуется начать транзакцию, а когда ее завершить.

Гммм... и как же живут все UoW-фреймворки?
Re[7]: транзакционность в business logic comenents
От: Ziaw Россия  
Дата: 02.06.10 08:50
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Какой транзакцией? Если у нас первая часть UoW (с извращённой точки зрения это просто генерация скрипта обновления) — нам ничего не нужно от ACID. Если вторая — атомарное внесение изменений — то это проблемы DAL, BLL максимум может явно потребовать (или запретить) целостность данных и явно указать scope для распределённых транзакций (вообще-то распределённость также должна инкапсулироваться DALом).


Z>>Один из вариантов реализации — протаскивание скоупа через thread context.

S>Вы который скоп имеете в виду? [ThreadStatic] переиспользуется потоками в пуле. У CallContext тоже есть свои нюансы
Автор: Sinix
Дата: 18.04.10
. Повторяю — проблема не в scope,а в наличии нескольких durable ресурсов.


Я лишь указал, что управлять транзакцией из DAL не получится.

Прблемы нескольких ресурсов это проблемы конкретной реализации. Скоуп может быть любой, не обязательно фреймворковский. Например Spring.Net умеет управлять транзакциями декларативно через AOP.

Z>>DAL (в общем случае) не имеет информации о том, когда требуется начать транзакцию, а когда ее завершить.

S>Гммм... и как же живут все UoW-фреймворки?

Управляют UoW из BLL.
Re[2]: транзакционность в business logic comenents
От: Ziaw Россия  
Дата: 02.06.10 12:07
Оценка:
Здравствуйте, Gridmer, Вы писали:

G>Можно записывать в БД каждое изменение объекта, но это приведёт к большому количеству мелких запросов к БД, что закончится замедлением работы приложения. Более того, это требует держать открытую транзакцию всё время работы приложения, что непрактично, если приложение обрабатывает несколько запросов одновременно. Ситуация ещё хуже, если необходимо следить за чтением из и БД, чтобы избежать неконсистентного чтения.


Очень спорный момент.
1. UoW это всегда замедление работы приложения, а большое количество мелких запросов которые он сможет оптимизировать — довольно редкий случай, чаще происходит наоборот.
2. Требование "держать транзакцию открытой все время работы приложения" феерический бред.
3. "что непрактично, если приложение обрабатывает несколько запросов одновременно", этот вывод я вообще не понял, хотя, если подумать из чего он делается...
4. Единственный нормальный способ избежать неконсистентного чтения — использование нужного уровня изоляции в транзакции. Все остальное либо сведется к этому под капотом,, либо будет работать лишь в частных случаях.
Re[7]: транзакционность в business logic comenents
От: IT Россия linq2db.com
Дата: 02.06.10 13:16
Оценка:
Здравствуйте, Sinix, Вы писали:

Z>>DAL (в общем случае) не имеет информации о том, когда требуется начать транзакцию, а когда ее завершить.

S>Гммм... и как же живут все UoW-фреймворки?

Кстати, хороший вопрос. А как UoW решают задачи, поставленные топик стартером?
Если нам не помогут, то мы тоже никого не пощадим.
Re[3]: транзакционность в business logic comenents
От: Gridmer Россия www.i-tt.ru
Дата: 02.06.10 15:43
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>1. UoW это всегда замедление работы приложения, а большое количество мелких запросов которые он сможет оптимизировать — довольно редкий случай, чаще происходит наоборот.


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

Z>2. Требование "держать транзакцию открытой все время работы приложения" феерический бред.


Возможно, но где-то бывает и такое. Имеется в виду, наверное, бизнес-транзакция.

Z>4. Единственный нормальный способ избежать неконсистентного чтения — использование нужного уровня изоляции в транзакции. Все остальное либо сведется к этому под капотом,, либо будет работать лишь в частных случаях.


Если под капотом еще и происходит оптимизация, то голосую за капот
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Re: транзакционность в business logic comenents
От: sto Украина http://overstore.codeplex.com
Дата: 02.06.10 21:22
Оценка: 1 (1)
Здравствуйте, AlSer, Вы писали:

AS>Доброго времени суток


AS>Как правильно реализовать понятие транзакций на уровне Business Logic Layer,

AS>ведь работа с базами данных должна осуществляеться в Data Access Layer.
AS>Например, компонент из BLL получает данные в виде business entities (или data transfer objects) из таблицы Table1 посредством компонента DAL, обрабатывает их и в результате обработки должен сохранить обработанные business entities обратно в Table1, а также в Table2 (в зависимости от условий еще и в Table3, Table4). И это все должно осуществиться как одна транзакция, т.е. если что-нибудь произойдет во время этой операции (какой-нибудь Exception), то первоначально извлеченные данные должны остаться такими как и были).
AS>Но... ведь BLL не контролирует транзакции (это все в ведении DAL). Как быть?
AS>Какие особенности использования ORM (NHibernate, EF) в этом случае?
Вам нужен, как уже много раз написали, TransactionScope, либо некий его аналог. Написать его не так сложно, как может показаться. Использовать его нужно будет в business logic layer, либо придется делать неатомарные методы в data access layer, которые частично (а если не повезет, то и полностью) будут дублировать (или содержать) бизнес логику. Кстати, Unit of Work здесь здорово помогает тем, что разделяет моменты изменения данных и момент их сохранения.

Гораздо сложнее со вторым вашим требованием, что при откате транзакции извлеченные данные должны остаться такими, как и были. Потому что обновление базы может изменять записываемые туда данные: вычисляемые поля, генерируемые идентификаторы, триггеры, в конце-концов.
There is no such thing as the perfect design.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.