Можно ли избежать неявной транзакции?

Обсуждение возникших проблем, предложений и ошибок SDAC компонентов
Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Можно ли избежать неявной транзакции?

Сообщение Rajoe » Ср 23 окт 2013 18:03

При выполнении ApplyUpdates компонента MSConnection самостоятельно сначала открывает транзакцию, затем по результатам либо фиксирует, либо откатывает. У меня довольно сложный процесс сохранения, который разбит на несколько частей, и все части должны быть заключены в транзакционные скобки. Но сделать это я не могу, так как уже первый ApplyUpdates завершает транзакцию. Можно ли как-то запретить MSConnection управлять транзакцией?

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: Можно ли избежать неявной транзакции?

Сообщение AndreyZ » Чт 24 окт 2013 10:35

На данный момент нет возможности избежать автоматической фиксации изменений при вызове метода TMSConnection.ApplyUpdates.
Мы добавили свойство TMSConnection.AutoCommit, это изменение войдет в следующий билд SDAC. Используя свойство AutoCommit, вы сможете контролировать фиксацию изменений следующим образом:

Код: Выделить всё

MSConnection1.AutoCommit := False;
// изменения
MSConnection1.ApplyUpdates;
// изменения
MSConnection1.ApplyUpdates;
MSConnection1.Commit;

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Можно ли избежать неявной транзакции?

Сообщение Rajoe » Чт 24 окт 2013 14:54

Спасибо. А в этом случае использование StartTransaction не предполагается? Открываться транзакция будет по-прежнему автоматически?

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: Можно ли избежать неявной транзакции?

Сообщение AndreyZ » Чт 24 окт 2013 15:19

Вы можете контролировать старт транзакции вызовом метода TMSConnection.StartTransaction до вызова TMSConnection.ApplyUpdates . Если Вы не стартовали транзакцию, она будет автоматически запущена при первом вызове TMSConnection.ApplyUpdates .

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Можно ли избежать неявной транзакции?

Сообщение Rajoe » Чт 24 окт 2013 15:51

Другими словами, она обязательно будет открыта, или мной через вызов StartTransaction, или автоматически из ApplyUpdates? То есть, отключить транзакцию вообще невозможно?

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: Можно ли избежать неявной транзакции?

Сообщение AndreyZ » Пт 25 окт 2013 07:53

Метод TMSConnection.ApplyUpdates отправляет изменения всех датасетов находящихся в режиме CachedUpdates на сервер. Транзакция обеспечивает корректное состояние базы данных. Если Вы хотите полностью управлять процессом отправки изменений датасетов на сервер, Вам следует использовать метод TMSQuery.ApplyUpdates вместо TMSConnection.ApplyUpdates. В данном случае транзакция не стартуется.

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Можно ли избежать неявной транзакции?

Сообщение Rajoe » Пт 25 окт 2013 10:24

Понятно, спасибо. Попробую использовать TMSQuery.ApplyUpdates. Просто мне показалось нелогичным такое несимметричное управление транзакцией: транзакция открывается обязательно, а вот завершается или нет - ещё посмотрим. Если обновление данных выполняется достаточно сложной процедурой, внутри которой в зависимости от условий могут быть организованы разные транзакции или не организованы вовсе, то на уровне этой процедуры невозможно определить, кто начал транзакцию, клиент или сервер, соответственно, кто должен принять решение об её откате или фиксации. Это накладывает ненужные ограничения на алгоритмы и приводит к необоснованному усложнению разработки. На мой взгляд, логичнее было бы отключать не завершение транзакции, а всю транзакцию, то есть, если свойство, аналогичное AutoCommit, установлено, то и BEGIN TRANSACTION, и COMMIT/ROLLBACK генерируются компонентой. Если это свойство сброшено, то программист сам вызывает StartTransaction, Commit и Rollback в случае необходимости, или не использует транзакцию вовсе, обеспечивая целостность данных на уровне БД. При такой реализации ограничений нет.
Например, у меня многие хранимые процедуры (практически любая) могут быть вызваны как из клиента, так и из других процедур или скрипта. При этом транзакции контролируются следующим образом:

Код: Выделить всё

declare @iRes int, @bTrans bit;
if @@trancount = 0
begin
	set @bTrans = 1;
	begin transaction;
end
else
	set @bTrans = 0;
set @iRes = 0;

--основной код с перехватом ошибок и установкой кода возврата в @iRes

if @bTrans = 1
begin
	if @iRes < 0
		rollback
	else
		commit;
end;
return(@iRes);
При таком подходе процедура не в состоянии определить, начал ли транзакцию клиент, или вызывающая процедура, или скрипт, и своей транзакции не откроет. Тогда закрывать транзакцию обязательно придётся на стороне клиента, и механизм управления завершением транзакции с помощью AutoCommit становится бесполезен. Если отключение транзакции на стороне клиента будет полным, то такого не произойдёт, и серверные процедуры отработают правильно. Можно сказать - не используйте такой подход в хранимых процедурах - но бывают ситуации, когда только на уровне процедуры можно принять решение, открывать ли транзакцию и сколько.

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: Можно ли избежать неявной транзакции?

Сообщение AndreyZ » Пн 28 окт 2013 14:24

По умолчанию, SDAC стартует и фиксирует транзакцию. При использовании свойства TMSConnection.AutoCommit, Вы можете контролировать транзакцию сами. Но наличие транзакции при вызове TMSConnection.ApplyUpdates мы считаем необходимым, поскольку при этом гарантируется целостность данных на сервере.
Если Вы стартуете транзакцию в хранимой процедуре, Вам следует фиксировать или откатывать ее в этой же процедуре, независимо вызвана ли она другой процедурой или клиентом. Изменения которые были произведены в транзакции будут зафиксированы на сервере только при вызове COMMIT и @@TRANCOUNT = 1. Более подробную информацию Вы можете найти по следующей ссылке: http://technet.microsoft.com/en-us/libr ... 90295.aspx

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Можно ли избежать неявной транзакции?

Сообщение Rajoe » Пн 28 окт 2013 16:44

Спасибо за ссылку, в курсе. Проблема не в том, чтобы правильно сохранить данные, а в том, чтобы сохранить их любой ценой. Вы заранее предполагаете бизнес-процесс, который должен быть правильным со всех сторон, и это работает в 95% случаев. Но бывают случаи, когда информация должна быть просто сохранена, с её корректностью будут разбираться потом отдельными методами. И это очень неудобно - несимметричное управление транзакцией. Я, если честно, никак не пойму смысла в отключении половины функциональности. То есть, программа местами не доступна для управления программисту, это усложняет работу, приходится искать обходные пути. Можно, конечно, в первой же строке хранимой процедуры написать rollback и дальше уже спокойно разбираться самому, но, согласитесь, это как-то странно выглядит, да и не всегда возможно. Очень, очень печально, что нельзя целиком управлять транзакцией.

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: Можно ли избежать неявной транзакции?

Сообщение AndreyZ » Вт 29 окт 2013 09:14

Метод TMSConnection.ApplyUpdates применяет множественные изменения сделанные в различных датасетах с помощью различных методов (выполнением SQL запросов, хранимых процедур и т.д.). Корректное поведение в данном случае является наличие транзакции. В противном случае, вызов TMSConnection.ApplyUpdates может привести к не целостному состоянию данных.
Вы предлагаете добавить в SDAC функциональность которая нарушает основное правило множественных изменений: наличие транзакционных скобок. Мы не планируем вводить такую функциональность в SDAC.
Если Вы хотите избежать транзакции которую стартует метод TMSConnection.ApplyUpdates, Вам не следует его использовать. Например, Вы можете использовать следующий код:

Код: Выделить всё

var
  i: integer;
  ds: TCustomDADataSet;
begin
  for i := 0 to MSConnection.DataSetCount - 1 do begin
    ds := TCustomDADataSet(MSConnection.DataSets[i]);
    if ds.UpdatesPending then
      ds.ApplyUpdates;
  end;
end;

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Можно ли избежать неявной транзакции?

Сообщение Rajoe » Вт 29 окт 2013 11:41

Спасибо за терпение! :) Перевёл всё на ApplyUpdates наборов данных и сделал свою управляемую транзакцию, всё работает, как хотел.

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: Можно ли избежать неявной транзакции?

Сообщение AndreyZ » Вт 29 окт 2013 12:12

Я рад что смог помочь.

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Можно ли избежать неявной транзакции?

Сообщение Rajoe » Чт 31 окт 2013 17:20

Всё же придётся ещё раз вернуться к этому вопросу. Что рекомендуется делать, если нужна распределённая транзакция?

AndreyZ
Devart Team
Сообщения: 328
Зарегистрирован: Чт 08 сен 2011 13:18

Re: Можно ли избежать неявной транзакции?

Сообщение AndreyZ » Чт 31 окт 2013 17:40

Что рекомендуется делать, если нужна распределённая транзакция?
Использовать компонент TMSTransaction. Подробную информацию Вы найдете здесь:
http://www.devart.com/sdac/docs/devart_ ... action.htm
http://www.devart.com/sdac/docs/work_tmstransaction.htm

Rajoe
Сообщения: 24
Зарегистрирован: Пн 24 сен 2012 15:16

Re: Можно ли избежать неявной транзакции?

Сообщение Rajoe » Вт 05 ноя 2013 14:35

Спасибо.

Закрыто