Задавайте вопросы, мы ответим
Вы не зашли.
Здравствуйте. Вопрос собственно в комментарии.
DELIMITER //
CREATE PROCEDURE `buy_item`(IN user_id INT, IN item_id INT)
BEGIN
DECLARE cost INT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
START TRNSACTION
SELECT `cost` INTO cost FROM `item` WHERE `item_id`=item_id;
UPDATE `user` SET `money`=`money`-cost WHERE `user_id`=user_id AND `money` >= cost;
/* Как здесь узнать деньги изменились или нет (нехватило денег) ?*/
INSERT INTO `inventory` (`item_id`, `user_id`) VALUES(item_id, user_id);
COMMIT;
END
Неактивен
DELIMITER //
CREATE PROCEDURE `buy_item`(IN user_id INT, IN item_id INT)
BEGIN
DECLARE cost INT;
DECLARE money INT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
START TRNSACTION
SELECT `cost` INTO cost FROM `item` WHERE `item_id`=item_id;
SELECT `money` INTO money FROM `user` WHERE `user_id`=user_id;
IF(money >= cost)
UPDATE `user` SET `money`=`money`-cost WHERE `user_id`=user_id AND `money` >= cost;
INSERT INTO `inventory` (`item_id`, `user_id`) VALUES(item_id, user_id);
END IF;
COMMIT;
END
Если я сделаю так? Есть вероятность, что `user`.`money` изменится между селектом и апдейтом `money`, другим запросом. Или запись заблокируется после SELECT на время транзакции?
Неактивен
На то и используется транзакция, чтобы не было других изменений во время транзакции.
Неактивен
Тогда вопрос. Как mysql понимает какую именно таблицу или запись блокировать? Заранее спасибо.
Неактивен
Зависит от уровня изоляции. Для этого случая подозреваю, что нужен уровень
SERIALIZABLE, но его, к сожалению, сломали в 5.1 и бага до сих пор открыта
Как рабочее решение — предлагаю Вам воспользоваться явным LOCK TABLES
перед соответствующими SELECT и UPDATE.
Неактивен
Хорошо допустим LOCK TABLES. Как это отразится если скрипт юзают около 1 млн.? Может быть лучше использовать GET_LOCK()?
Отредактированно cooler (22.04.2010 19:21:13)
Неактивен
GET_LOCK по id записи? Можно попробовать. Но тогда бы я лучше брал mutex внутри
приложения — быстрее получится.
Неактивен
А можите привести пример как в моем случае обходить баг в транзакции? буду очень признателен.
Неактивен
Ну так в Вашем коде дописать только явный уровень нужно:
SELECT `cost` INTO cost FROM `item` WHERE `item_id`=item_id;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN;
SELECT `money` INTO money FROM `user` WHERE `user_id`=user_id;
IF(money >= cost)
UPDATE `user` SET `money`=`money`-cost WHERE `user_id`=user_id AND `money` >= cost;
INSERT INTO `inventory` (`item_id`, `user_id`) VALUES(item_id, user_id);
END IF;
COMMIT;
Неактивен
Спс большое. И еще вопрос вот 2 запроса
SELECT `cost` INTO cost FROM `item` WHERE `item_id`=item_id;
SELECT `cost` INTO cost FROM `item` WHERE `item_id`=item_id LIMIT 1;
Второй запрос выполнится быстрее?
Неактивен
Если в первом возвращается всего одна строка, то нет, очевидно
Если больше одной строки — то да. Даже планы выполнения запросов могут быть
разные — в зависимости от количества строк и индексов.
Неактивен