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

Вниз

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

 
Юрий Зотов ©   (2010-09-06 22:41) [0]

AS400, DB2, J2SE, двузвенка.
Опуская детали, схема кода выглядит так:

StartTransaction;
try
 DeleteRecord(ID); // ID -первичный ключ
 DoSomething;
 InsertRecord(ID); // Таблица и ID те же, что и в DeleteRecord
 Commit
except
 RollBack;
 WriteLog("Фиг вам")
end;

Коннект к БД единственный и весь этот код работает через него. Казалось бы, все тривиально и железно. Но неожиданно возникают фокусы.

1. При выполнении InsertRecord возникает исключение DuplicateKey. Ради эксперимента выполнил DeleteRecord и InsertRecord в раздельных транзакциях - и все отлично сработало, но в боевом режиме так, конечно, делать нельзя.

Вопрос 1 - какого хрена InsertRecord не видит, что запись удалена?

2. После выполнения этого кода записи c ID в таблице нет (хотя ДО его выполнения она была). В логе есть честное сообщение об ошибке - то есть, исключение было перехвачено и откат состоялся.

Вопрос 2 - какого хрена не откатилось удаление записи?


 
Inovet ©   (2010-09-06 22:55) [1]

> [0] Юрий Зотов ©   (06.09.10 22:41)
> какого хрена InsertRecord не видит, что запись удалена?

Так для других транзакций она живая.


 
Inovet ©   (2010-09-06 22:57) [2]

> [0] Юрий Зотов ©   (06.09.10 22:41)
> Вопрос 2 - какого хрена не откатилось удаление записи?

Может RollBack для транцакции не тот, что надо, настройка транзакции в смысле.


 
Юрий Зотов ©   (2010-09-06 23:07) [3]


> Inovet ©   (06.09.10 22:55) [1]

А другие транзакции тут ни при чем. Delete и Insert выполняются в ОДНОЙ транзакции, поэтому:

1. Insert должна видеть изменения, сделанные в Delete и поэтому не должна давать никаких Duplicate key.
2. А уж если исключение все же возникло, то откатываться должны ВСЕ изменения.


 
Джо ©   (2010-09-06 23:12) [4]

Может, случилась классика жанра и проблема в 13-й строке? :)
Все же чудес не бывает и проблема либо в самой используемой технологии (что маловероятно), либо в неприведенном фрагменте кода. Допустим, в DoSomething транзакция заканчивается, да мало ли что.


 
Petr V. Abramov ©   (2010-09-06 23:12) [5]


> Вопрос 1 - какого хрена InsertRecord не видит, что запись
> удалена?

ээээ, Юр Сергеевич, еврейский InsertRecord или православный sql-ный insert statement??? это две большие разницы в общем случае. хрен его знает, что там жабный метод делает из соображений как получше бы.


 
Юрий Зотов ©   (2010-09-06 23:42) [6]

> Джо ©   (06.09.10 23:12) [4]

Просмотрел весь код раз 100 - ничего не нашел. И потом:

1. Если до вызова Insert транзакция коммитится, то Insert тем более обязан видеть изменения, сделанные в Delete - а ведь не видит.

2. А если до вызова Insert транзакция откатывается, то обязана восстанавливаться удаленная запись - а ведь не восстанавливается.

Странность как раз в том, что происходят две ВЗАИМОИСКЛЮЧАЮЩИЕ ошибки.


 
Inovet ©   (2010-09-07 02:28) [7]

> [6] Юрий Зотов ©   (06.09.10 23:42)
> Странность как раз в том, что происходят две ВЗАИМОИСКЛЮЧАЮЩИЕ ошибки.

Может таки там в этих "AS400, DB2, J2SE, двузвенка" внетранзакционные какие дела с ключами происходят? Действительно, как Пётр выше сказал, попробовать то же, но без обёрток. Это я так предполагаю только, ибо не трогал ДБ2.


 
sniknik ©   (2010-09-07 03:10) [8]

было что-то похожее давно... с ADO, при использовании "клиентской  транзакции" (той что методом у компонента ADOConnection) с тех пор и перестал так делать, только запросами, когда они гарантированно "серверные". и хоть говорят, что они в те же запросы переводятся, но видать не у всех...

в общем попробуй запросами (если там у тебя это возможно).

> ибо не трогал ДБ2.
то же самое, просто по аналогии.


 
Anatoly Podgoretsky ©   (2010-09-07 09:13) [9]

Что такое  DeleteRecord, InsertRecord
Проблема наверно там
Почему не хочешь написать SQL запрос?
DELETE FROM tbl WHERE ID=:ID


 
Polevi ©   (2010-09-07 11:49) [10]

у меня возникает иногда похожая проблема с MS SQL
в транзакции сначала добавляется запись в справочную таблицу, затем в таблицу фактов.
иногда возникает форейн кий констрэйнт, как будто первой операции не было.
используется стандартный SqlCommand


 
Юрий Зотов ©   (2010-09-07 11:54) [11]


> Что такое  DeleteRecord, InsertRecord

Упрощенно, вот что:

private void deleteRecord(Integer iD) throws SQLException {
 String sql = "delete from TABLE where ID = ?";
 Object[] params = new Object[] { iD };
 connection.executeUpdate(sql, params);
}

private void insertRecord(Integer iD) throws SQLException {
 String sql = "insert into TABLE (ID, FLD) values (?, ?) ";
 Object[] params = new Object[] { iD, fldValue };
 connection.executeUpdate(sql, params);
}

Здесь connection и fldValue - приватные поля класса. Транзакция стартует, коммитится и откатывается через этот самый connection. Удаление и вставка, как видно из кода, производятся через него же (то есть, именно в этой транзакции).

Еще из кода видно, что удаление и вставка производятся как раз прямым SQL (точнее, через метод connection.executeUpdate, но поскольку этот метод из стандартного пакета java.sql уже оттестирован миллионы раз сотнями тысяч программеров по всему миру, то подозревать его в неправильности вряд ли можно.


 
12 ©   (2010-09-07 12:04) [12]

а может у connection есть какое св-во, типа AutoCommit, кторое плавает..

зы
может и фигню сказал, зато самому ЮЗ :)


 
Юрий Зотов ©   (2010-09-07 12:11) [13]


> 12 ©   (07.09.10 12:04) [12]

Как раз не фигня - именно такое свойство у него действительно есть. По умолчанию оно - true, и старт транзакции состоит как раз в том, чтобы выставить его в false. После этого начинают работать методы commit и rollback.

Но даже если бы было AutoCommit = true, то Insert тем более был бы обязан видеть изменения, сделанные в Delete - а ведь не видит (поскольку дает Duplicate key).


 
12 ©   (2010-09-07 12:16) [14]


> Юрий Зотов ©   (07.09.10 12:11) [13]

это понятно, но

> кторое плавает..

может сбрасыватся туда-сюда где то по коду выше-ниже?


 
oxffff ©   (2010-09-07 12:17) [15]


> Юрий Зотов ©   (07.09.10 12:11) [13]
>
> > 12 ©   (07.09.10 12:04) [12]
>
> Как раз не фигня - именно такое свойство у него действительно
> есть. По умолчанию оно - true, и старт транзакции состоит
> как раз в том, чтобы выставить его в false. После этого
> начинают работать методы commit и rollback.
>
> Но даже если бы было AutoCommit = true, то Insert тем более
> был бы обязан видеть изменения, сделанные в Delete - а ведь
> не видит (поскольку дает Duplicate key).


Может запускается >1 копии кода в разных транзакциях?
И одна копия коммитится раньше другой успешно. А вторая приводит к subj?


 
Юрий Зотов ©   (2010-09-07 12:34) [16]


> 12 ©   (07.09.10 12:16) [14]

Проверял поиском. Нет такого.


> oxffff ©   (07.09.10 12:17) [15]

Тоже думал, но это исключено. Программа серверная (практически служба, демон) - и в ней предприняты меры для блокировки повторного запуска (да и в списке задач система всегда показывает только 1 экземпляр). Еще программа многопоточная, но данный кусок кода жестко синхронизирован (и синхронизация действительно работает, это много раз проверено).


 
oxffff ©   (2010-09-07 12:45) [17]


> > oxffff ©   (07.09.10 12:17) [15]
>
> Тоже думал, но это исключено. Программа серверная (практически
> служба, демон) - и в ней предприняты меры для блокировки
> повторного запуска (да и в списке задач система всегда показывает
> только 1 экземпляр). Еще программа многопоточная, но данный
> кусок кода жестко синхронизирован (и синхронизация действительно
> работает, это много раз проверено).


Может все же залогировать работу в таблицу и посмотреть логи?


 
Компромисс   (2010-09-07 12:45) [18]

Юрий Зотов

Вы бы оригинальный java код привели, может и помог кто.


 
oxffff ©   (2010-09-07 12:49) [19]


> Может все же залогировать работу в таблицу и посмотреть
> логи?


Очень часто совершенно странные и непонятно как возникающие ошибки случаются банально из-за опечаток, un/комментирования кода, copy paste.


 
Юрий Зотов ©   (2010-09-07 12:50) [20]


> oxffff ©   (07.09.10 12:45) [17]

Сделано с самого начала. Там отладочные сообщения и трасса Exception (включая имена классов, методов и номера строк). Видно, что вылетает именно в Insert из-за Duplicate key, а до этого все хорошо.


> Компромисс   (07.09.10 12:45) [18]

Реальный код слишком большой.


 
oxffff ©   (2010-09-07 12:51) [21]


> oxffff ©   (07.09.10 12:45) [17]
>
> > > oxffff ©   (07.09.10 12:17) [15]
> >
> > Тоже думал, но это исключено. Программа серверная (практически
>
> > служба, демон) - и в ней предприняты меры для блокировки
>
> > повторного запуска (да и в списке задач система всегда
> показывает
> > только 1 экземпляр). Еще программа многопоточная, но данный
>
> > кусок кода жестко синхронизирован (и синхронизация действительно
>
> > работает, это много раз проверено).
>
>
> Может все же залогировать работу в таблицу и посмотреть
> логи?


После удаления проверять select есть запись или нет. Опять же в лог.
И все станет понятно. :)


 
Компромисс   (2010-09-07 13:05) [22]

Похоже на это?

http://www.mail-archive.com/pgsql-general@postgresql.org/msg132161.html


 
sniknik ©   (2010-09-07 13:06) [23]

> По умолчанию оно - true, и старт транзакции состоит как раз в том, чтобы выставить его в false. После этого начинают работать методы commit и rollback.
по описанию больше похоже на кешированные обновления ("батчапдетемоде"), т.е. "транзакция" формируется на клиенте (о чем и говорил).
там также будет (описанный "глюк"), т.к. сервер не знает что запись с таким ключом удалена, и порядок обновлений неизвестен. (вернее если insertRecord именно инсерт, как с некоторыми таблицами раньше BDE могло, а не append, то именно известен, и неправилен... запрос на вставку будет раньше удаления)


 
Anatoly Podgoretsky ©   (2010-09-07 13:32) [24]

> sniknik  (07.09.2010 13:06:23)  [23]

То что кеширование это одназначно.


 
Ega23 ©   (2010-09-07 13:48) [25]

Вложенные транзакции поддерживаются?


 
Ega23 ©   (2010-09-07 13:51) [26]

Что-то типа
Begin Tran1
 Begin Tran2
   Delete(ID)
 Commint Tran2
 Begin Tran3
   Insert
 Commit Tran3
Commit Tran1


 
toto   (2010-09-07 16:51) [27]

Какая версия стоит на АS400? Если не ошибаюсь начиная с V4R5 надо :

Information de journalisation :              
 Actuellement journalisé  . . . . . . :   OUI


 
Юрий Зотов ©   (2010-09-08 17:33) [28]


> Какая версия стоит на АS400? Если не ошибаюсь начиная с
> V4R5 надо :

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


 
Юрий Зотов ©   (2010-09-08 17:45) [29]

В общем, причину так и не нашел, пришлось искать обходные маневры. По советам Олега и Петра, ничего не удаляя, сделал запись новых данных во временную таблицу - а потом MERGE.

Есть и более простой (но плохой, ИМХО) вариант - тоже ничего не удалять, а перед записью проверять SELECT"ом существовование записи и если она есть - то UPDATE, иначе INSERT. Хотя, учитывая [16] этот вариант, может быть и неплохим вовсе.

Что скажете, гуру БД?


 
Empleado ©   (2010-09-08 17:57) [30]


> а перед записью проверять SELECT"ом существовование записи
> и если она есть - то UPDATE, иначе INSERT

Этот вариант мне кажется более логичным, особенно в плане целостности данных.
Хотя, я не гуру, могу ошибаться.


 
vrem   (2010-09-08 19:06) [31]

полагается писать транСакции


 
Ega23 ©   (2010-09-08 19:13) [32]


> Есть и более простой (но плохой, ИМХО) вариант - тоже ничего
> не удалять, а перед записью проверять SELECT"ом существовование
> записи и если она есть - то UPDATE, иначе INSERT. Хотя,
> учитывая [16] этот вариант, может быть и неплохим вовсе.


Сильно СУБД-зависимо. Да и структуру таблицы надо смотреть (индексы всякие).
У меня, например, в аналогичной ситуации просто офигенный выигрыш в скорости дала конструкция на T-SQL
TRY
 INSERT ...
CATCH
 UPDATE...
END


Может тут тоже что-то такое нужно, если SQL-диалект позволяет?


 
boriskb ©   (2010-09-08 19:34) [33]

> [29] Юрий Зотов ©   (08.09.10 17:45)
> В общем, причину так и не нашел


Жалко.
Как только ветка появилась, мне вспомнилось, что нечто подобное лет 5-7 назад на MS SQL у меня случалось.
Силился вспомнить - как я выкручивался. Не вспомнилось
Думал - здесь решат и вспомню.

А может и я не "решил", а "выкрутился" ?


 
Ega23 ©   (2010-09-08 19:42) [34]


> Думал - здесь решат и вспомню.


Суррогатный ключ и уникальный индекс - наше всьё!


 
Petr V. Abramov ©   (2010-09-08 20:29) [35]


> Ega23 ©   (08.09.10 19:42) [34]

а какая тут-то разница суррогатный или с акцизной маркой?


 
Anatoly Podgoretsky ©   (2010-09-08 21:31) [36]

> Юрий Зотов  (08.09.2010 17:45:29)  [29]

Я часто использую схему DELETE + Insert, только с прямыми запросами. Все
работает да и транзакция в большинстве случаев лишнее. Обычно нет нужды
откатывать удаленое, кроме редких случаев. А для MSSQL я вообще пишу это как
одну команду.
И делаю это чтобы не узнавать есть запись или нет.
У меня есть посторонняя бухсистема, там последовательно delete+insert
обычная норма, особенно перерасчеты и тоже как правило в рамках одной
команды. Смотрел профайлером.


 
Ega23 ©   (2010-09-08 21:35) [37]


> там последовательно delete+insert обычная норма,


Есть подозрение, что Update в MSSQL это и есть Delete + Insert


 
Игорь Шевченко ©   (2010-09-08 21:36) [38]

Задал бы ты, Юра, свой вопрос в
http://sql.ru/forum/actualtopics.aspx?bid=5

там про DB2 тебе все расскажут, как и почему, а может и про твою беду помогут


 
Игорь Шевченко ©   (2010-09-08 21:37) [39]


> Есть подозрение, что Update в MSSQL это и есть Delete +
> Insert


можешь вклиниться между ? Нет ? Тогда ты неправ


 
Ega23 ©   (2010-09-08 21:43) [40]


> можешь вклиниться между ? Нет ? Тогда ты неправ

Ты меня не так понял.
Впрочем, предлагаю не здесь и не сейчас, а 14-го в соответствующем месте. :)


 
Petr V. Abramov ©   (2010-09-08 21:48) [41]


> а 14-го в соответствующем месте. :)
>

соберутся великие спецы по AS/400, жабе DB/2 :)


 
Ega23 ©   (2010-09-08 21:51) [42]


> соберутся великие спецы по AS/400, жабе DB/2 :)


Если бы ты меня не продинамил, то мы бы с тобой это легко и непринуждённо обсудили бы. Прямо сегодня. Без проблем. Без жалости. Без пощады.


 
Anatoly Podgoretsky ©   (2010-09-08 21:58) [43]

> Ega23  (08.09.2010 21:35:37)  [37]

Логически это и есть, но это вроде и физически.


 
Petr V. Abramov ©   (2010-09-08 21:58) [44]


> Ega23 ©   (08.09.10 21:51) [42]

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


 
Игорь Шевченко ©   (2010-09-08 22:10) [45]

Ega23 ©   (08.09.10 21:43) [40]


> Ты меня не так понял.


Предлагаю принять за аксиому, что Update - это Update, единая и неделимая операция, а не Delete+Insert и не Insert+Delete.


> Впрочем, предлагаю не здесь и не сейчас, а 14-го в соответствующем
> месте. :)


Увы, не выйдет


 
Ega23 ©   (2010-09-08 22:12) [46]


> Предлагаю принять за аксиому, что Update - это Update, единая
> и неделимая операция, а не Delete+Insert и не Insert+Delete.


Я вот это имел ввиду:


> Anatoly Podgoretsky ©   (08.09.10 21:58) [43]
>
> Логически это и есть, но это вроде и физически.


 
Petr V. Abramov ©   (2010-09-08 22:14) [47]


> но это вроде и физически.

а вроде в мАскве не считается


 
Anatoly Podgoretsky ©   (2010-09-08 22:20) [48]


> Предлагаю принять за аксиому, что Update - это Update, единая
> и неделимая операция, а не Delete+Insert и не Insert+Delete.
>

Например в Акцесс делается неявная транзакция,  новые данные пишутся в новое место, потом старое освобождается, за счет этого и живуч. И чем это не удаление и вставка? И разрастание базы.
Вроде бы в MS SQL точно также. Кто то проводил иследования за страницами, новые данные в новое место. А MSSQL как и большинство серверов без транзакций не работают. Так и транзакцию легче сделать.


 
jack128_   (2010-09-08 22:24) [49]


> Anatoly Podgoretsky ©   (08.09.10 22:20) [48]

для версионников такой подход - вообще единственно возможный.


 
Petr V. Abramov ©   (2010-09-08 22:24) [50]


> Anatoly Podgoretsky ©   (08.09.10 22:20) [48]


> Кто то проводил иследования за страницами, новые данные
> в новое место.

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


 
Petr V. Abramov ©   (2010-09-08 22:25) [51]


> Petr V. Abramov ©   (08.09.10 22:24) [50]

в блоке резервировать


 
Anatoly Podgoretsky ©   (2010-09-08 22:38) [52]

> jack128_  (08.09.2010 22:24:49)  [49]

Ну так и считаем, что это удаление, ведь старой записи физически по
окончанию транзакции не остается.


 
Ega23 ©   (2010-09-08 22:40) [53]

Я собственно к чему. Вот в триггере есть таблица inserted. И есть deleted. А вот updated - чё-та нету...


 
Anatoly Podgoretsky ©   (2010-09-08 22:54) [54]

Чего гадать, обратимся к первоисточнику

> В таблице deleted находятся копии строк, с которыми работали
> инструкции DELETE или UPDATE. При выполнении инструкции
> DELETE или UPDATE происходит удаление строк из таблицы триггера
> и их перенос в таблицу deleted. У таблицы deleted обычно
> нет общих строк с таблицей триггера.
>
> В таблице inserted находятся копии строк, с которыми работали
> инструкции INSERT или UPDATE. При выполнении транзакции
> вставки или обновления происходит одновременное добавление
> строк в таблицу триггера и в таблицу inserted. Строки таблицы
> inserted являются копиями новых строк таблицы триггера.
>
> Транзакция обновления аналогична выполнению операции удаления
> с последующим выполнением операции вставки
; сначала старые
> строки копируются в таблицу deleted, а затем новые строки
> копируются в таблицу триггера и в таблицу inserted.


 
Petr V. Abramov ©   (2010-09-08 23:01) [55]


> Ega23 ©   (08.09.10 22:40) [53]
>
> Я собственно к чему. Вот в триггере есть таблица inserted.
>  И есть deleted. А вот updated - чё-та нету...

это все потому что у insert-update-delete нету returning кляузы, у FB в 2.0 и то вроде б есть, а в этом мсскуле все ректально через триггер.


 
Игорь Шевченко ©   (2010-09-08 23:05) [56]

Anatoly Podgoretsky ©   (08.09.10 22:54) [54]

С точки зрения таблиц в триггерах


 
Дмитрий Тимохов   (2010-09-08 23:05) [57]

Я, возможно, невнимательно прочел, но что говорит profiler?
Нежели прямо такой и будет код: сначала delete, а потом insert и срубится по ошибке? Ну может правла кеширование клиентское?

Хотя к чему это я - СУБД то не тот, который я знаю.
Ну профайлер то должен быть!


 
sniknik ©   (2010-09-09 01:43) [58]

> [29] Юрий Зотов ©   (08.09.10 17:45)
> В общем, причину так и не нашел
причина ясна. более менее, проверить только осталось. просто кое кто не хочет в нее верить...

у вас там не транзакция, а клиентская эмуляция. вот попробуй для проверки последовательность запросов типа (именно запросов, без оберток и их методов вроде StartTransaction и т.д.)
CREATE TABLE aaa (f1 INT PRIMARY KEY, f2 INT)
INSERT INTO aaa (f1, f2) VALUES (1, 1)
INSERT INTO aaa (f1, f2) VALUES (2, 2)
INSERT INTO aaa (f1, f2) VALUES (3, 3)
BEGIN TRANSACTION
DELETE FROM aaa WHERE f1=2
INSERT INTO aaa (f1, f2) VALUES (4, 4)
DELETE FROM aaa WHERE f1=3
INSERT INTO aaa (f1, f2) VALUES (5, 5)
INSERT INTO aaa (f1, f2) VALUES (3, 3)
INSERT INTO aaa (f1, f2) VALUES (2, 2)
COMMIT TRANSACTION
SELECT * FROM aaa


всегда работало. может синтаксис отличатся, но логика вряд ли.



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

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

Наверх





Память: 0.61 MB
Время: 0.006 c
2-1285069581
guest
2010-09-21 15:46
2010.12.19
Почему не работает?


15-1284025204
И. Павел
2010-09-09 13:40
2010.12.19
Как узнать логин, под которым клиент вошел в MS SQL?


2-1285337414
Guestt
2010-09-24 18:10
2010.12.19
Как передать в функцию ссылку на другую функцию?


2-1285159212
Darvin
2010-09-22 16:40
2010.12.19
Длина файла с путем больше 260 байт


15-1284008288
Miko
2010-09-09 08:58
2010.12.19
задержка





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский