Реализация транзакций

ran

Новичок
Реализация транзакций

Здравствуйте, возникла вопрос по транзакциям.
Если выполнить SET AUTOCOMMIT=1, то перед insert/update запросами нет необходимости выполянять START TRANSACTION, а после COMMIT/ROLLBACK.
Или все же лучше самому контролировать этот процесс так:
PHP:
try{
    $db->query("SET AUTOCOMMIT=0");
    $db->query("START TRANSACTION");
    $db->query($userQuery);
    $db->query("COMMIT");
}
catch (exception $e){
    $db->query("ROLLBACK");
    throw new CDatabaseException($e->getMessage());
}
Просто еще подумал о том, что в транзакцию может входить несколько запросов, и если один из них не выполнился, то необходимо откатить результаты выполнения предущих, а с SET AUTOCOMMIT=1 это не получится.
Получается, что для пакетной реализации транзакций необходим свой какой-то модуль или класс, который будет управлять транзакциями?
Или я неправильно понял использование транзакций в MySql? :confused:

-~{}~ 21.12.06 09:39:

Этот вопрос решен, создал отдельный класс, с помощью которого управляю транзакциями (по умолчанию в транзакцию входит каждый INSERT/UPDATE запрос). Но один раз возникла ошибка :
1213(ER_LOCK_DEADLOCK)
Message: Deadlock found when trying to get lock; try restarting transaction.
Получается, что поступило несколько запросов на изменение одной записи, и время ожидания завершения транзакции у одного из них истекло.
Не могу сообразить, как поступать, если такая ошибка будет повторяться?
Заранее спасибо.
 

Апельсин

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

Рестартовать транзакцию.
 

ran

Новичок
Сделал цикл, в котором выполняю запрос, и если получаю DEADLOCK ошибку, пытаюсь повторить транзакцию, а иначе выход из цикла и возврат результатов. Думаю 50 попыток более чем достаточно.
Интересно получается, а что, во время транзакции запись блокируется и на чтение? Установлен уровень изоляций REPEATABLE-READ.
 

Апельсин

Оранжевое создание
Смотря что ты делаешь в этой транзакции.
Если транзакция вида:
begin;
select * from t1;
commit;

то тогда этот consistent non-locking read.

а SELECT .. FOR UPDATE или SELECT .. LOCK IN SHARE MODE ставят локи.

ну и если интересно более подробно про транзакции и блокировки можно всегда почитать в мануале:
http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-model.html

кроме того какой был последний detected deadlock можно посмотреть в SHOW INNODB STATUS, заодно и узнаешь какие транзакции каких блокировок ждали.
 

ran

Новичок
Апельсин
спасибо большое, теперь понятнее.
А посмотреть последний DEADLOCK не могу, потому что был не сегодня, сервер mysql рестартовался и SHOW INNODB STATUS ничего не показал. Думаю проблем с этим уже не будет, так как ошибка возникла 1 раз за несколько месяцев, а в следующий раз в логах посмотрю, которые приложение пишет(добавил при такой ошибки лог статуса innoDB). А в транзакции выполнялся запрос INSERT ... SELECT.
:)
 

MadMike

Новичок
Insert ... select - зло для транзакций ;)
Я у себя уже давно запретил делать такое без моего апрува.

-~{}~ 23.12.06 02:42:

ran
По поводу избежания дедлоков есть разные темы. Пример - getlock() - release_lock().
"Разделяй и властвуй" - это именно про дедлоки. Думаю, этого будет достаточно для решения проблемы.
 

ran

Новичок
MadMike
Т.е. если перед start transaction я установлю lock функцией get_lock, то в течении времени, которое указано этой функции, я не получу deadlock? И все записи, которые используются в запросах до вызова release_lock будут заблокированы?
 

Апельсин

Оранжевое создание
ran, не совсем ..

get_lock()/release_lock() - это некий контроль локов на уровне приложения. Что-то вроде установки флага "залочено".
Т.е. на самом деле никакие никакие локи не устанавливаются, ставятся просто флаги типа "залочено1", "залочено2", а другой тред может проверять установлено оно или нет.
 

MadMike

Новичок
Собственно, deadlock'и можно отлавливать только на уровне приложения, выше MySQL.
 

ran

Новичок
Апельсин
т.е. можна устанавливать локи по определенному ID запросов в системе и не давать выполнять запросы к этим же данным....
Спасибо еще раз, думаю это использую в будущем, а сейчас всего лишь реализовал TransactionClass и при ошибке дедлока делаю n-е количество попыток снова выполнить запрос (а может просто добавлю установку локов в этот класс - сейчас только массив выполненых транзакций и текущая транзакция).
Апельсин, MadMike
Вопрос не требующий ответа, просто интересно, что вы предпочитаете использовать: get_lock()/release_lock() или же какое-то другое решение? :)
 

MadMike

Новичок
ran
Мы в нескольких частях проекта используем get_lock(). Проблем вроде не наблюдается, нагрузка приличная :)
 

Апельсин

Оранжевое создание
> т.е. можна устанавливать локи по определенному ID запросов в системе и не давать выполнять запросы к этим же данным....

не ID запросов и не локи. Метки, видимые из других тредов. Физически ничего при этом не лочится.
 

MadMike

Новичок
ran
Смысл в том, чтобы запретить параллельное выполнение конкретной операции.
Вызов get_lock() идентичен по смыслу системному вызову flock().
 

ran

Новичок
Ясно, нашел еще пару интересных тредов по этой теме :)
http://phpclub.ru/talk/showthread.php?threadid=82746&goto=nextoldest
http://phpclub.ru/talk/showthread.php?threadid=73006&rand=10
 
Сверху