2017-01-15 13 views
1

Я пишу хранимую процедуру. В этом у меня есть следующие MySQL операторы вставки:Блокировка таблицы для вставок из MySQL InnoDB Сохраненная процедура

INSERT INTO `Address`(`countryCode`, `addressLine1`, `addressLine2`, `postcode`, `region`, `city`) VALUES (country, addressLine1, addressLine2, postcode, region, city); 
INSERT INTO `UserAddress`(`username`, `creationDate`, `addressId`) VALUES (username,NOW(),(SELECT addressId FROM Address ORDER BY addressId DESC LIMIT 1)); 

Как вы можете видеть, я выступаю вставку на таблицу адресов, а затем использовать авто увеличивается «AddressID» в подзапроса на следующей строке. Теперь, если между этими двумя операторами другая транзакция будет вставлять что-то в таблицу Address, я бы ввел неправильный адрес в таблицу UserAddress. Я предполагаю, что мне нужно заблокировать таблицу Address, пока эти инструкции выполняются.

После долгих поисков я нашел следующий код, чтобы заблокировать адресную таблицу:

SELECT addressId FROM Address FOR UPDATE; 

Будет ли это работать для вновь добавленных строк? Если нет, что бы?

+2

Вы всегда будете вставлять два ряда вместе? Если да, зачем вставлять их в отдельные таблицы? Я думаю, что у вашего дизайна есть проблема. – GurV

+1

Если вам действительно нужно это сделать, я могу подумать об использовании транзакции. Но, как говорит @GurV, у вас может возникнуть проблема с дизайном. –

+0

@GurV Как это проблема дизайна? Идея состоит в том, что пользователи могут иметь несколько адресов. Кроме того, один адрес может быть нескольких пользователей. Кроме того, у адреса есть дата создания. Мне нужна таблица между таблицами «Адрес» и «Пользователь», а затем правильно? –

ответ

0

Вот почему именно они изобрели LAST_INSERT_ID

INSERT INTO `Address`(`countryCode`, `addressLine1`, `addressLine2`, `postcode`, `region`, `city`) VALUES (country, addressLine1, addressLine2, postcode, region, city); 
INSERT INTO `UserAddress`(`username`, `creationDate`, `addressId`) VALUES (username,NOW(),LAST_INSERT_ID()); 

Нет необходимости в замках или операций или даже хранимых процедур для задачи захвата последнего идентификатора. Просто сделайте это в своем приложении.

+0

И это безопасно? Потрясающие! –

+0

рад помочь – e4c5

+0

'LAST_INSERT_ID()' является локальным для соединения; следовательно, «валютный сейф». –

1

В идеале вы должны сделать это внутри Transaction, используя «START TRANSACTION;» и «COMMIT». Вам также необходимо установить autocommit в 0 (он включен по умолчанию). Here - это документация для Сделок и автообмена.

Пока ваши обновления обернуты внутри транзакции и устанавливается isolation level, изменения, сделанные другой транзакцией, не повлияют на вашу транзакцию.

+0

Хороший дизайн, чтобы обернуть каждую из моих хранимых процедур в START TRANSACTION; и «COMMIT в рамках процедуры? –

+1

Не все, кроме битов, которые нуждаются в изоляции, как и тот, который вы упомянули в вопросе. –

+2

Подумайте об этом так: В этом: Запрос 1: возьмите немного денег из своего банковского счета; Запрос 2: положите эти деньги на свой сберегательный счет. Что делать, если сервер разбился между запросом 1 и запросом 2? Это классический пример необходимости «BEGIN; запрос 1; запрос 2; COMMIT; 'так, чтобы либо _both_ преуспеть, либо _neither_. Если ваше приложение имеет что-то подобное, вам нужны транзакции. –