Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 TransactionScope, обработка вложенных транзакций, атомарность  [new]
Dmitry Gurianov
Member

Откуда:
Сообщений: 651
Всем привет!

Пример такой. В соответствии с бизнес-логикой, некая операция содержит в себе два действа, которые должны быть выполнены по принципу все-или-ничего. Допустим, при увольнении сотрудника следует также начислять ему выходное пособие.

В методе FireEmployee бизнес-слоя я помещаю вызов методов DeleteEmployee(empId) и AddPayment(empId, amount) слоя доступа к данным, и, поскольку необходима атомарность, оборачиваю это дело в TransactionScope (псевдокод):
public void FireEmployee(int empId, int amount){
	using (TransactionScope ts = new TransactionScope())
	{
		(new EmployeeRepository()).DeleteEmployee(empId);
		(new EmployeeRepository()).AddPayment(empId, amount);
		ts.Complete();
	}
}


Каждый из методов DeleteEmployee и AddPayment, в свою очередь, вызывает хранимки Employee_Del и Payment_Ins, в которых довольно сложная логика, LOCK-и и другое, что не может быть реализовано средствами ORM.

До сих пор эти хранимки имели приличный вид с точки зрения атомарности и поддерживали принцип "все-или-ничего" за счет оборачивания их тел в try/catch, begin tran/savepoint/commit/rollback. С использованием TransactionScope появились проблемы: savepoint-ы не поддерживаются в распределенной транзакции (которая автоматически стартуется блоком TransactionScope из-за наличия в нем более одного содеинения с БД), а любой rollback в хранимке откатит все, включая транзакцию верхнего уровня.

Внимание, вопрос. Что делать, чтобы сохранить атомарность в хранимках? Также принимаются прочие замечания.

Пути решения, которые мне не нравятся:

1) поскольку со вложенными транзакциями, а точнее rollback-ами, нормально не получится, следует открыть одну-единственную транзакцию TransactionScope, а все хранимки писать без поддержки транзакций. "Минус" в том, что, в зависимости от кода, вызвавшего процедуру, может получиться, что выполнилась только часть операций хранимки. Например, в хранимке типа
CREATE PROC Payment_Ins
-- params
as
	-- операция 1: начислить денех
	-- операция 2: тут ошибка!!111
	-- операция 3: занести в протокол
GO

при внешнем COMMIT-e выполнится только 1-я операция. Процедурка совсем не атомарна.

2) Оставить механизм savepoint-ов в хранимках, но переделать логику приложения так, чтоб TransactionScope открывал обычную, а не распределенную транзакцию - читай, сделать, чтоб все хранимки вызывались в одном соединении. Придется городить огород в бизнес-логике и подтягивать туда connection-ы.

3) В очередной раз признать бесполезность слоя бизнес-логики как такового и делать транзакционность в слое доступа к данным, явно указывая коннекшены.

4) Вообще запилить одну хранимку, в которой сделать все, что хочется. И к чертям все BL-ы и DAL-ы.

Есть идеи?
23 апр 12, 23:20    [12459941]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
invm
Member

Откуда: Москва
Сообщений: 9827
Просто интересно: Какой сакральный смысл в распределенных транзакциях, если работа идет с одним сервером?
23 апр 12, 23:49    [12460068]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
Dmitry Gurianov
Member

Откуда:
Сообщений: 651
invm
Просто интересно: Какой сакральный смысл в распределенных транзакциях, если работа идет с одним сервером?


Изначальный смысл был в том, чтобы бизнес-логика ничего не знала об sql-connections, а, не зная о них, получаются несколько соединений. Это неправильно?
23 апр 12, 23:52    [12460082]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
invm
Member

Откуда: Москва
Сообщений: 9827
Dmitry Gurianov
Изначальный смысл был в том, чтобы бизнес-логика ничего не знала об sql-connections, а, не зная о них, получаются несколько соединений. Это неправильно?
Смысл использовать распределенные транзакции есть, если, прошу прощения за тавтологию, имеется хоть какая-то вероятность, что система станет распределенной. Иначе вы только себе граблей набросаете.

Почему бы не инкапсулировать работу с sql-connections на DAL?

Для процедур можно использовать примерно такой шаблон:
create procedure SomeSchema.SomeProc
as
begin
 set nocount on;
 
 declare @tc int = @@trancount;
 
 begin try
 
 if @tc = 0
  begin tran;
 
 ...
 
 if @tc = 0
  commit; 

 end try
 begin catch
  ...
  if @tc = 0 and @@trancount > 0
   rollback;
  ...
 end catch;
 
end;
24 апр 12, 00:39    [12460205]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
invm
Просто интересно: Какой сакральный смысл в распределенных транзакциях, если работа идет с одним сервером?
А чёта тут вообще не вижу что она распределённая. О чём разговор?
Может кто-то не умеет готовить?

invm, согласен, что логика сервера должна быт на сервере, и не желателен множественный вызов.
Хотя иногда есть случаи (очень редкие, не этот) когда лучше и проще это допускать.
24 апр 12, 12:35    [12461930]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Dmitry Gurianov
С использованием TransactionScope появились проблемы: savepoint-ы не поддерживаются в распределенной транзакции (которая автоматически стартуется блоком TransactionScope из-за наличия в нем более одного содеинения с БД), а любой rollback в хранимке откатит все, включая транзакцию верхнего уровня.

Внимание, вопрос. Что делать, чтобы сохранить атомарность в хранимках? Также принимаются прочие замечания.
Все вешесказанные посты можно считать OffTop-ом.
Пример вводит в заблуждение, ибо
{
	(new EmployeeRepository()).blaBla1
	(new EmployeeRepository()).blaBla2
}
Само по себе глупо.

Представим, что там разные БД, допустим даже MSSQL и Oracle.
24 апр 12, 12:41    [12462011]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
invm
Member

Откуда: Москва
Сообщений: 9827
Mnior
invm
Просто интересно: Какой сакральный смысл в распределенных транзакциях, если работа идет с одним сервером?
А чёта тут вообще не вижу что она распределённая. О чём разговор?
Может кто-то не умеет готовить?
Я так понял, что в
public void FireEmployee(int empId, int amount){
	using (TransactionScope ts = new TransactionScope())
	{
		(new EmployeeRepository()).DeleteEmployee(empId);
		(new EmployeeRepository()).AddPayment(empId, amount);
		ts.Complete();
	}
}
Из-за нежелания ТС явно рулить соединениями, DeleteEmployee и AddPayment будут выполняться в разных соединениях. В результате TransactionScope начинает распределенную транзакцию.
24 апр 12, 12:46    [12462079]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
SAVE TRANSACTION (Transact-SQL)
BOL
Инструкцию SAVE TRANSACTION нельзя применять в распределенных транзакциях, запускаемых явно с применением инструкции BEGIN DISTRIBUTED TRANSACTION, или повышением уровня с локальной транзакции.
Мать моя женщина.
Из-за банальной возможности написать неправильно они тупо запретили.
+ Как это неправильно?
use (TransactionScope) {
	...
	MsSqlClient.Exec('SAVE POINT XXX');
	OraClient.Exec('BlaBla');
	MsSqlClient.Exec('ROLLBACK XXX');
	...
}
MS в своей ипостаси.
#спасибомикрософтзаэто
24 апр 12, 12:59    [12462253]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
Dmitry Gurianov
Member

Откуда:
Сообщений: 651
invm
Из-за нежелания ТС явно рулить соединениями, DeleteEmployee и AddPayment будут выполняться в разных соединениях. В результате TransactionScope начинает распределенную транзакцию.


Именно так. И не то, чтоб из-за нежелания, просто я пытаюсь натянуть действительность на широко предлагаемые паттерны. Касательно двух одинаковых репозиториев - ошибка, считайте, что
public void FireEmployee(int empId, int amount){
	using (TransactionScope ts = new TransactionScope())
	{
		(new EmployeeRepository()).DeleteEmployee(empId);
		(new PaymentRepository()).AddPayment(empId, amount);
		ts.Complete();
	}
}
24 апр 12, 13:01    [12462274]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Dmitry Gurianov
Касательно двух одинаковых репозиториев - ошибка, считайте, что ...
Всё равно можно поспорить.
Конекшин это контекст исполнения, а не свойство конкретного объекта.
Т.е. это свойтво фабрик объектов, которая настраивается глобально, а не прописано явно в коде.
Так что опологёты ООП с полным правом могут начать срач.
24 апр 12, 16:56    [12464264]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
Dmitry Gurianov
Member

Откуда:
Сообщений: 651
Mnior
Dmitry Gurianov
Касательно двух одинаковых репозиториев - ошибка, считайте, что ...
Всё равно можно поспорить.
Конекшин это контекст исполнения, а не свойство конкретного объекта.
Т.е. это свойтво фабрик объектов, которая настраивается глобально, а не прописано явно в коде.
Так что опологёты ООП с полным правом могут начать срач.


Я не уверен, что правильно понял вашу мысль, но попробую ответить на то, как понял :)
Если предположить, что существует бизнес-целостность, то наиболее подходящей реализацией для нее в C# служит TransactionScope. И хоть она внутри себя рулит именно sql-коннекшнами, нас не должно это заботить. Поэтому вытаскивание в БЛ именно Sql-connection я считаю нарушением принципа разделения ответственности. Но практика снова показывает, что реальность прозаичнее.
24 апр 12, 17:30    [12464583]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Dmitry Gurianov
Но практика снова показывает, что реальность прозаичнее.
Отмазка говнокода?
(new EmployeeRepository()).BlaBla
(new PaymentRepository()).BlaBla
Должно быть от одного SqlConnection и точка. Т.е. абстракции завязаны на реализации (см. паттерн Bridge).
Не сделаете нормально - это ваши грабли. Рефакториг апосля дорого будет стоить.

И технология MARS тем более режется на корню.
А с другой стороны, рулит Linked Servers. Т.е. это ещё вопрос где линия конфигурации проходит.
Т.е. БД это более контекст исполнения и до фабрик не дотягивает.

Но это OffTop. В общем виде (MS SQL / Oracle / Linked) задача не решается и это проблема.
Надо обсуждать. Таких НО у MS много. Абстракции текут кокретно. И мешают жить очень сильно. В риски это надо записывать и учитывать.
Особенно когда сама MS конфетку предлагает, а она с говнецом.
24 апр 12, 19:13    [12465320]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
Dmitry Gurianov
Member

Откуда:
Сообщений: 651
Тока не надо про говнокод :) Вызов методов репозиториев описан в туевой хуче паттернов, начиная от NerdDinner и MusicStore, и о коннекшенах там речи не идет.
25 апр 12, 04:53    [12466765]     Ответить | Цитировать Сообщить модератору
 Re: TransactionScope, обработка вложенных транзакций, атомарность  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Dmitry Gurianov, я вам про Фому, вы мне про Ерёму.
Какой нафиг конекшион в патернах?!
Там всё на смысле завязано. База это ближе к реализации некоторой абстракции Employee.
Поэтому скорее всего надо смотреть на Структурные шаблоны проектирования
25 апр 12, 18:49    [12471087]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить