Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Откат транзакции в InterBase. [D6, XP]


Drowsy ©   (2009-09-15 17:45:00) 

Должен ли происходить откат на внесённые в таблицу А изменения и если да, то почему може не происходить?

TransactionAll - на базе
TransactionA - на выборке из таблицы А.
TransactionВ - на выборке из таблицы В.

TransactionAll.StartTransaction;

try

 TransactionA.StartTransaction;
 // изменения на А
 TransactionA.Commit;

 TransactionB.StartTransaction;
 // изменения на B
=> появление Exception.
 TransactionB.Commit;

 TransactionAll.Commit;
except
 TransactionAll.RollBack;
end;


Sergey13   (2009-09-16 11:09:00) [1]

> [13] Юрий Зотов ©   (16.09.09 10:21)
> 'select Max(ID) + 1 into NewID from A for update';

Пробовать не начем, но сомневаюсь, что такой запрос вообще отработает. For update блокирует от изменения записи, а тут в наличии только результат функции.
Но и идеологически так делать нельзя. Нужно запросить
select Gen_ID(N,Gen_name) from rdb$database
где N - число вставляемых записей
В результате получим максимальный зарезервированный ИД-шник. От него уже считать минимальный и промежуточные.


MsGuns   (2009-09-16 10:39:00) [2]

ИМХО, налицо непонимание сущности понятия "транзакция".
Советую о транзакциях, в том числе и об уровнях их изоляции, почитать у Вострикова с Ковязиным. Более доступного и полного объяснения механизма транзакций не встречал.

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


Юрий Зотов   (2009-09-16 10:29:00) [3]

Кстати, вопрос к знатокам: достаточно ли для блокировки таблицы A на время транзакции указать 'for update', или нужны другие телодвижения?


Юрий Зотов   (2009-09-16 10:21:00) [4]

> Drowsy   (16.09.09 06:20) [11]

Псевдокод:

Transaction.StartTransaction;
try
 // 1. Получаем ID новой записи в таблице A и лочим ее
 'select Max(ID) + 1 into NewID from A for update';
 // 2. Вставляем запись в таблицу A, явно указывая ID = NewID
 'insert into A...';
 // 3. Вставляем запись в таблицу B, явно указывая ForeignKey = NewID  
 'insert into B...';
 Transaction.Commit
except
 Transaction.RollBack;
 raise
end;


Sergey13   (2009-09-16 08:49:00) [5]

> [11] Drowsy   (16.09.09 06:20)

Может все таки код напишешь вместо своих
> Сделал всё в одной транзакции

> генерируется ошибка dead lock, с указанием на Foreign Key таблицы В
Что-то сомнительно про dead lock. Ключ не находит - понятно. В данном случае ключ для главной таблицы надо не генерить в тригере, а получать заранее, перед началом транзакции, для всех вставляемых записей.


Drowsy   (2009-09-16 06:20:00) [6]

А - главная таблица с автоинкрементным ключом
В - связанная таблица

Сделал всё в одной транзакции.
Теперь такое:
После инсерта записи в А, при попытке ввести связанную запись в В, генерируется ошибка dead lock, с указанием на Foreign Key таблицы В.


Германн   (2009-09-16 02:33:00) [7]


> Кстати, в секции except после отката транзакции надо бы
> как-то обработать исключение (хотя бы выдать юзеру сообщение).
>  В простейшем случае - просто raise.
>

Ну да. Хотя бы затычку!


Юрий Зотов   (2009-09-16 01:50:00) [8]

> Drowsy

Кстати, в секции except после отката транзакции надо бы как-то обработать исключение (хотя бы выдать юзеру сообщение). В простейшем случае - просто raise.


Германн   (2009-09-16 00:38:00) [9]


> Drowsy   (15.09.09 18:49) [5]
>
>

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


Юрий Зотов   (2009-09-16 00:30:00) [10]

> Drowsy   (15.09.09 18:49) [5]

Зачем так усложнять и путать? Если откатывать нужно ВСЕ изменения -  значит, и транзакция должна быть только ОДНА. Причем стартовать ее надо ПЕРЕД try, а не внутри (иначе, если при старте транзакции возникнет исключение, то код попытается ее откатить - а раз она не стартовала, то и откатывать нечего).

Transaction.StartTransaction;
try
 ... // все изменения
 Transaction.Commit
except
 Transaction.RollBack
end;


Inovet   (2009-09-15 18:54:00) [11]

> [5] Drowsy   (15.09.09 18:49)

Одну пока оставь.


Drowsy   (2009-09-15 18:49:00) [12]

А в моём примере TransactionA  и TransactionВ не являются вложенными по отношению к TransactionAll?
Я сейчас сделал так :

try
TransactionAll.StartTransaction;

TransactionA.StartTransaction;
// изменения на А

TransactionB.StartTransaction;
// изменения на B
=> появление Exception.

TransactionA.Commit;
TransactionB.Commit;
TransactionAll.Commit;
except
TransactionA.RollBack;
TransactionB.RollBack;
TransactionAll.RollBack;
end;

Работает, но дико долго стало работать. Когда после изменений делал коммит на каждом наборе, то хотя отката при ексепшене не происходило (как, по пояснениям DRPASS - спасибо!, и должно было случиться), но работало несравнимо быстрее.


DrPass   (2009-09-15 18:36:00) [13]


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

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


> Руководства врубаются сразу в тонкости и детали, а для начинающих,
>  с нуля и "на пальцах" никому не интересно
> писать...

А что там объяснять для начинающих, по крайней мере, в отношении Interbase? Транзакция объединяет группу операций с базой данных. Все, что выполняется в рамках одной и той же транзакции, можно разом применить через commit, или разом отменить через rollback. Каких-либо там глобальных транзакций, или вложенных друг в друга в Interbase нет.


Drowsy   (2009-09-15 18:13:00) [14]

Я запутался в Commit, RollBack, CommitRetaining, RollBackRetaining, параметрах транзакций...
Что в каких случаях применяется когда и как......
Руководства врубаются сразу в тонкости и детали, а для начинающих, с нуля и "на пальцах" никому не интересно
писать...


Drowsy   (2009-09-15 18:03:00) [15]


> неясно, в рамках какой транзакции ты делал изменения в таблице
> А.

TransactionA связана с TIBQury - выборке из таблицы А.
И ей делается коммит.

Мне нужно сделать пакетно изменения в таблицах и откатить все, если при
изменении хоть одной возникло исключение...


DrPass   (2009-09-15 17:56:00) [16]


> Должен ли происходить откат на внесённые в таблицу А изменения
> и если да, то почему може не происходить?

Неизвестно. Т.к. из данного кода неясно, в рамках какой транзакцииты делал изменения в таблице А. Если это была TransactionA, то откат, конечно же, происходить не должен. Если TransactionAll, то должен


Наверх

Титульная страница Поиск, карта сайта Написать письмо