Форум: "Прочее";
Текущий архив: 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-SQLTRY
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-го в соответствующем месте. :)
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2010.12.19;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.004 c