Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.05.14;
Скачать: [xml.tar.bz2];

Вниз

Транзакции   Найти похожие ветки 

 
parovoZZ ©   (2006-04-16 21:40) [0]

Есть следующее:
  try
   ADOConnection.BeginTrans;
   ADOCmd.Execute ();

  except
   ADOConnection.RollbackTrans;

  end;
   ADOConnection.CommitTrans;


Так вот допустим, что во время выполнения операции произошёл обрыв связи с сервером. Куда тогда уйдёт инструкция Rollback?

И потом: обязательно ли явно объявлять транзакцию на операнд SELECT?


 
Johnmen ©   (2006-04-16 21:50) [1]

А зачем после роллбека делать коммит? :)


> Куда тогда уйдёт инструкция Rollback?


В песок...


> обязательно ли явно объявлять транзакцию на операнд SELECT?


Не обязательно даже на простой инсерт, например.


 
Джо ©   (2006-04-16 22:09) [2]

BeginTrans также вынеси перед try, потому, что если транзакция не началась (возникло исключение), то и откатывать нечего.


 
sniknik ©   (2006-04-16 22:39) [3]

> BeginTrans также вынеси перед try
BeginTrans как и все остальное на клиенте выкинуть нафиг...

писать в скрипте команды ADOCmd

BEGIN TRANSACTION
...
INSERT ...
...
COMMIT TRANSACTION

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

p.s. для одиночного инсерта самому транзакцию стартовать... это чтото типа паранойи (болезнь такая), если не лечить то и программа "с приветом" будет. ;)


 
Джо ©   (2006-04-16 23:08) [4]

> [3] sniknik ©   (16.04.06 22:39)
> BeginTrans как и все остальное на клиенте выкинуть нафиг...
>
> писать в скрипте команды ADOCmd
>
> BEGIN TRANSACTION
> ...
> INSERT ...
> ...
> COMMIT TRANSACTION

Ну, я сделал поправку к конкретному коду, а не пытался "вправить" мировозрение :)
К тому же, я сомневаюсь, чтобы твой твой подход можно было назвать "универсальным". Есть ситуации (даже не говоря о различиях в СУБД), когда совершенно не представляется разумным запихнуть логическую транзакцию в один скрипт ADOCmd.


 
Джо ©   (2006-04-16 23:12) [5]

Чтобы не быть голословным, вот простейшая ситуация.
Несколько ADOCmd вызывают ХМ на сервере, в зависимости от результатов предыдущих ХП определяются параметры (и необходимость) вызова следующих и т.п. Все вызовы должны проходить в рамках единой транзакции. Т.е, один из случаев, когда логика определяется на клиенте.

Всё, теперь я готов к получению своей порции тухлых помидоров :)


 
parovoZZ ©   (2006-04-17 11:02) [6]

1. Я это всё к тому, что, допустим, надо вставить пару-тройку записей по мегабайту каждая. И при передачи последних 1 кб связь оборвалась. Тогда AdoCommand вызовет исключение, в свою очередь RollbackTrans тоже вызовет исключение. Сервер, допустим, MySQL, так и не дождавшись ответа, отвергнет вставку...или как?

2. Если надо реализовать каскадное удаление записей, то лучше делать через хранимую процедуру?

// А что, ADOCommand поддерживает несколько SQL инструкций??? Сильно тоКА не бейте, учусь же.


 
Sergey13 ©   (2006-04-17 11:14) [7]

2 [6] parovoZZ ©   (17.04.06 11:02)
>1. Сервер, допустим, MySQL, так и не дождавшись ответа, отвергнет вставку...или как?
Должен отвергнуть. В этом и смысл транзакций.

>2. Если надо реализовать каскадное удаление записей, то лучше делать через хранимую процедуру?
Каскадное удаление лучше делать через каскадное удаление по внешнему ключу. 8-)


 
sniknik ©   (2006-04-17 11:27) [8]

> надо вставить пару-тройку записей по мегабайту каждая.
они зависимы друг от друга? т.е. если не вставить последнюю то первая (к примеру) смысла не имеет? если имеет то не имеет смысла транзакция (неявная на обеспечение целосности самой записи и так будет). размер записи тут совсем не причем.

> А что, ADOCommand поддерживает несколько SQL инструкций???
столько сколько поддерживает "Любая" база...


 
sniknik ©   (2006-04-17 11:30) [9]

упс.
> Сервер, допустим, MySQL
не обратил внимания... тогда про неявную транзакцию для записи не в курсе... в принципе должна быть но х.ч. как оно там в нем на самом деле...


 
parovoZZ ©   (2006-04-17 16:14) [10]


> Каскадное удаление лучше делать через каскадное удаление
> по внешнему ключу. 8-)

Я имею ввиду SQL запрос вызывать из хранимой процедуры или из клиента? Или всё равно ( с точки зрения запуска транзакций)?


> > А что, ADOCommand поддерживает несколько SQL инструкций?
> ??
>столько сколько поддерживает "Любая" база...

С ADOQuery ничего не вышло. Только одна за один сеанс.


> > надо вставить пару-тройку записей по мегабайту каждая.
> они зависимы друг от друга? т.е. если не вставить последнюю
> то первая (к примеру) смысла не имеет? если имеет то не
> имеет смысла транзакция (неявная на обеспечение целосности
> самой записи и так будет). размер записи тут совсем не причем.
>

Ну сами же сказали, что один инсерт оборачивать в транзакцию смысла не имеет. Ну обернём десять... Тогда что?


 
Sergey13 ©   (2006-04-17 16:26) [11]

2 [10] parovoZZ ©   (17.04.06 16:14)
> Я имею ввиду SQL запрос вызывать из хранимой процедуры или из клиента? Или всё равно ( с точки зрения запуска транзакций)?

Абсолютно.

>Ну сами же сказали, что один инсерт оборачивать в транзакцию смысла не имеет. Ну обернём десять... Тогда что?
Лучше 100000000 сразу! 8-)
Надо "оборачивать" столько, сколько нужно - не больше и не меньше.


 
parovoZZ ©   (2006-04-18 19:15) [12]


> писать в скрипте команды ADOCmd BEGIN TRANSACTION...INSERT
> ......COMMIT TRANSACTION


Не понял, а как условие отката создать?


 
Sergey13 ©   (2006-04-19 09:18) [13]

>Не понял, а как условие отката создать?
С помощью try...except


 
parovoZZ ©   (2006-04-19 21:50) [14]

Прямо внутри процедуры? MySQL поймёт?


 
sniknik ©   (2006-04-19 23:02) [15]

> Прямо внутри процедуры? MySQL поймёт?
а причем сдесь MySQL? в вопросе база "Любая"

пример для MSSQL "Прямо внутри процедуры"

BEGIN TRANSACTION
INSERT INTO Table2 (ParID) VALUES (1000)
INSERT INTO Table1 (ID) VALUES (1000) -- ID автоинкремент, так будет ошибка, чего и добиваемся
IF @@error <> 0
 ROLLBACK TRANSACTION -- а вот и "откат"
ELSE
 COMMIT TRANSACTION

хотя конечно пример бредовый, специально задана неправильная последовательность и запись в "незаписываемое" поле, для наглядности.  

правильнее было бы
BEGIN TRANSACTION
INSERT INTO Table1 DEFAULT VALUES
INSERT INTO Table2 (ParID) VALUES (@@Identity)
COMMIT TRANSACTION
и без всяких откатов. связь будет обеспечена т.к. выполнение в одном пакете, а единственное почему 1н запрос сработает, а второй нет (исключая конечно кривые руки которые к примеру разные типы связке сделали) это экстренный "слет" сервера, ну типа в этот момент электричество кончилось... но тогда и коммит не сработает и тразакция очистится при перерестарте.


 
parovoZZ ©   (2006-04-21 22:13) [16]

Так, что имеем в сухом остатке...
Транзакции лучше писать в скрипте, а не пологаться на ADOConnection. Т. е. запрос

INSERT INTO Messages (Message, Author, Equipment, Date_Time, Category) VALUES (:prmMessage, :prmUser, :prmID, Now(), :prmCateg)


надо дополнить типа этого

BEGIN TRANSACTION
INSERT INTO Messages (Message, Author, Equipment, Date_Time, Category) VALUES (:prmMessage, :prmUser, :prmID, Now(), :prmCateg)
IF @@error <> 0  ROLLBACK TRANSACTION
ELSE  COMMIT TRANSACTION

А чем ADOConnection плох в этом плане?


 
sniknik ©   (2006-04-21 22:50) [17]

> надо дополнить типа этого
этот запрос ничем дополнять не надо, нет связанных/зависяших друг от друга данных...
а вообще читай ответы...  в [3] [8] уже говорил про одиночный инсерт... или у тебя транзакции "идея фикс"? ктото сказал что это круто?

> А чем ADOConnection плох в этом плане?
попыткой "рулить" транзакциями с клиента, "приучением" делать длительные разрывы между началом и завершением транзакции... так привыкают, что начинают ими юзеровскому вводу "cansel" делать..., неполноценностью команд в нем по сравнению с командами sql сервера. (см. BOL). + не нравятся они мне (и это самое главное ;), зачем делать убого с "разрывом" если можно "спрессовать" все в один неделимый пакет? а если нет такой возможности, по логике программы и надо разделить, то зачем делать кусок проги в другом стиле (sql команда универсальна, а вот с конекта процедуру в пакет не впихнеш).


 
Джо ©   (2006-04-21 23:18) [18]

> [17] sniknik ©   (21.04.06 22:50)

Пока я постиг 2 причины, по которым плохо управлять транзакциями с помощью TADOConnection: (1) они тебе не нравятся и (2) некоторые плохие программисты используют их не по назначению :).
А как же насчет [4],[5,. Пример там довольно мутно описан, но, если понадобится, могу и поподробней.

Я не придираюсь, мне на самом деле интересно, так как рел. СУБД стал заниматься недавно.


 
Sergey Masloff   (2006-04-21 23:38) [19]

parovoZZ ©   (16.04.06 21:40)  

 try
  ADOConnection.BeginTrans;
  ADOCmd.Execute ();

 except
  ADOConnection.RollbackTrans;

 end;
  ADOConnection.CommitTrans;

1) Как сказал Джо начало транзакции перед try
2) Коммит перед except
3) Длинные транзакции страшны не для всех СУБД ;-)))


 
Sergey Masloff   (2006-04-21 23:48) [20]

Кстати и возможность на сервере написать COMMIT поддерживается (по принципиальным соображениям!) далеко не всеми СУБД.


 
sniknik ©   (2006-04-22 00:00) [21]

> (1) они тебе не нравятся
это самая важная причина на самом деле. субьективное ошущение данное в реальности на подсознательном уровне бытия... (почти шутка ;)

насчет [4] [5], ну вообще вначеле описана ситуация с единственным вызовом (Execute) команды/пакета... т.е. разделять искуственно еще и на "транзакционные" команды когда можно все в один обьеденить, глупо. один пакет выполнится более вероятно чем несколько последовательных (он же пришол на сервер и выполняется, а не пришла часть работает, следующая ждет... т.е. более растянуто во времени получается, вероятнее сбой в сети).

но дальше написанно, да есть ситуации когда надо стартануть транзакцию, после выполнить несколько действий не вкладывающихся в один скрипт, и после всего закрыть ее.
есть, но зачем использовать для работы кастрированные версии команд, если есть полные?
сравни
ADOConnection.BeginTrans
и (BOL)
SET TRANSACTION ISOLATION LEVEL { READ COMMITTED | READ UNCOMMITTED | REPEATABLE READ | SERIALIZABLE }
BEGIN TRAN [ SACTION ] [ transaction_name | @tran_name_variable [ WITH MARK [ "description" ] ] ]

что стоит выполнить это в первом/последнем ADOCommand? или пусть даже выделив в отдельно выполняемые, все одно лучше чем BeginTrans.
ладно можно пользоваться не всем, но не заходя в BOL даже просто знать о возможности не будеш.

и потом, BeginTrans/... это общий метод для всех (типа) sql серверов... а если сервер/провайдер не поддерживает транзакций? что будет? а скорее всего ничего не будет, и ошибки не даст, метод то есть и вызван правильно. зато получим "логическую мину", пишем и закладываемся на целостность данных которых может и не быть.


 
sniknik ©   (2006-04-22 00:16) [22]

нда... [19]

ну давай на примере (это для Джо).
Есть следующее: //пусть есть
ADOConnection.BeginTrans; //стартовали... время посылки команды/пакета мизерное, не учитываем
try
 ADOCmd.Execute (); //пакет "ушол" на сервер, и выполняется, ну скажем 5 мин, на 3й "отвалилась" сеть
except
 ADOConnection.RollbackTrans; //придет сюда по ошибке, и снова "обломится" сети то нет...
end;
ADOConnection.CommitTrans; //и опять "облом".... уже с выдачей сообщения, подтверждения нет...

что будет в "моем" варианте, старт/комит внутри в команде
try
 ADOCmd.Execute ();
 //пакет "ушол" на сервер (время посылки помним - мизер),
 //выполняется, на 3й "отваливается" сеть... ну и что, пакет то выполняется сервером, он упешно доработает и подтвердит транзакцию...
except
end;

выбирай. какой вариант развития событий тебе "ближе и родней"?


 
Джо ©   (2006-04-22 00:51) [23]

> [21],[22] sniknik ©

С некоторыми соображениями согласен. Но, опять же, как единственно верный совет "писать всегда так" принять не могу :)
Несколько соображений.

(1) Вот, скажем, ты говоришь, что в качестве альтернативы можно использовать родной SQL-вский скрипт "в первом/последнем ADOCommand". Но это противоречит тому, что ты всячески пытаешься предостеречься от обрывов связи. То есть, один из твоих доводов-таки отпадает, ибо при обрыве связи безразлично было ли ADOConnection.BeginTrans или скрипт в отдельном ADOCmd.

(2) Вернусь к своим баранам :) Упрощая, сейчас имею следующую ситуацию (абстрактный псевдокод):

Connection.BeginTrans;
// весь блок ОБЯЗАН выполниться в единой транзакции
res1 := Command.Execute (ХП1);
res2 := LibraryRoutine (res1);
Command.Execute (ХП(res2));
Connection.CommitTrans;

Как видим, запихнуть это в один скрипт не выйдет. Запихнуть это в одну ХП на сервер тоже не выйдет. Ситуацию с переписыванием LibraryRoutine на языке хранимой процедуры даже и не рассматриваю: допустим (а это так и есть), она сложна, ресурсоемка и это заняло бы слишком много времени.

Если кому интересно, попинайте, пожалуйста, мой подход. Что касается меня, то я не вижу в нем особого криминала, нормальных альтернативных решений не вижу тоже. Заранее могу согласиться с тем, что из-за недостатка опыта я изобретаю велосипеды и горожу невесть что :)


 
sniknik ©   (2006-04-22 00:59) [24]

> Но, опять же, как единственно верный совет "писать всегда так" принять не могу :)
про "единственно верный" это ты сам придумал, перечитай что я говорил на самом деле еще раз...


 
Джо ©   (2006-04-22 01:02) [25]

> [24] sniknik ©   (22.04.06 00:59)
> про "единственно верный" это ты сам придумал, перечитай
> что я говорил на самом деле еще раз...

Да ничего я не придумал. То есть, в том смысле, что я не приписывал тебе высказывание "о единственно верном пути". Я таким образом хотел подчеркнуть старую истину об известном овоще :)


 
Sergey Masloff   (2006-04-22 04:47) [26]

Блин привет полный, горло болит спать не могу :(

sniknik ©   (22.04.06 00:16) [22]
Давай тебе пример;-)

что будет в "моем" варианте, старт/комит внутри в команде
try
ADOCmd.Execute ();
//пакет "ушол" на сервер (время посылки помним - мизер),
//выполняется, на 3й "отваливается" сеть... ну и что, пакет то выполняется сервером, он упешно доработает и подтвердит транзакцию...
except
end;

1) между except и end хоть что-то черкнуть не забывай. Я понимаю что в любом реальном коде ты так не напишешь. Я понимаю что и Джо это понимает. Но мало ли неокрепших умов последуют примеру буквально. Лучше перестраховаться ИМХО
2) Все прекрасно. Только если я как клиент отвалюсь а ты там для меня все сделал на сервере, то это все прекрасно только я об этом не узнаю. Че делать-то мне. Я бронировал билет. Отвалился. Теперь я сижу и думаю - а что там было-то? Бронировать мне новый? Или есть у меня уже?

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

Так что ситуации разные бывают когда и твой способ хорош когда и по-другому не помешает.


 
sniknik ©   (2006-04-22 10:09) [27]

> 1) между except и end хоть что-то черкнуть не забывай.
... ну это я просто "отсек лишнее" в предыдушем примере, выкинул оттуда ненужное для "моего" сценария, а самом деле и там в предыдушем обработки ошибки нет, тоже не хорошо так писать. (просто тут получилось виднее, блок остался пустым ;)

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

тут у меня возражений то и не было, возражение было против ADOConnection.BeginTrans;, самой формы. хотя бы просто для однотипности написания в програме/ах, ну раз в одном месте пишем одним вариантом, и невозможно использовать второй, то почемубы второй вообще не использовать если он легко заменяется первым?. т.е. почему не написать
ADOCommand.CommandText:= "BEGIN TRANSACTION Bron";
ADOCommand.Execute;
или если уж экономить строки...
ADOConnection.Execute("BEGIN TRANSACTION Bron");

не лучше ???

тем более это не одно и тоже, есть возможность добавить имя/маркировку транзакции, предварительно установить уровень изоляции. явно ее стартануть... (BeginTrans не стартует явно, судя по профайлеру, оно просто говорит чтобы не закрывалась автоматическая, для одной команды, все последующие уже в ее контексте выполняются.) не знаю как, но такое "смешение стилей" возможно может привести к путанице, чтото останется неподтвержденным... с потерей данных (потом будет "чудо!" все работает, но иногда перезагружаю комп последние данные исчезли...). ну это конечно из области предположений, фантазии, чтобы проверить надо использовать да еще и долго, но это именно то почему это мне не нравится, изза таких вот домыслов, и почему я этим пользоваться не буду. (и другим не советую. тем более альтернатива не сложнее)


 
Sergey Masloff   (2006-04-22 10:26) [28]

sniknik ©   (22.04.06 10:09) [27]
>ADOConnection.Execute("BEGIN TRANSACTION Bron");
На мой взгляд лучше. Но я почти не работал с ADO а все компоненты работы с ораклом с которыми я работаю делают именно так как нужно (аналог твоего BEGIN TRANSACTION  с параметрами) так что я не истина в какой-либо инстанции.


 
SergP ©   (2006-04-22 10:37) [29]


> Так вот допустим, что во время выполнения операции произошёл
> обрыв связи с сервером. Куда тогда уйдёт инструкция Rollback?
>


Уйдет в никуда. Да и если произошел обрыв, то при следующем соединении ты не увидишь изменений сделанных в предыдущий раз, если транзакция не была подтвержджена. Т.е. обрыв - это своего рода тоже некий RollBack. ИМХО.



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2006.05.14;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.011 c
15-1145353533
Pazitron_Brain
2006-04-18 13:45
2006.05.14
Попала в руки флэшка


2-1145860080
valdemot
2006-04-24 10:28
2006.05.14
Проценты


15-1145281500
oldman
2006-04-17 17:45
2006.05.14
задачки школьникам задают...


15-1145250201
Ega23
2006-04-17 09:03
2006.05.14
С Днём рождения! 16 апреля


2-1145709298
Ку Ку
2006-04-22 16:34
2006.05.14
Дополнительная кнопка





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский