Если вы хотите сделать это классическим способом, выполните следующие действия.
Сначала мы можем согласиться, что url
- это естественный первичный ключ. В любом случае вам нужен индекс в этом столбце для ускорения поиска:
CREATE UNIQUE INDEX url_references_idx ON url_references(url);
После этого, если вы выполните:
INSERT INTO url_references (url) VALUES ($url);
у вас два сценария:
• INSERT
успешно. Это означает, что ваш $url
является новым, и вы можете продолжить:
INSERT INTO posts (id, post_content) values (NULL, $postContent);
SELECT LAST_INSERT_ID(); // This will return $post_id
UPDATE url_references SET post_id = $post_id WHERE url = $url;
COMMIT;
В этом сценарии блокировка вновь вставленной строки в url_references
гарантирует, что другой поток перейдет во 2-й сценарий, если 1-я транзакция успешно зафиксирована (или 1-й сценарий, если она не удалась).
• Ошибка INSERT
. Это означает, что ваш $url
уже известен, и вы можете продолжить:
SELECT post_id FROM url_references WHERE url = $url;
UPDATE posts SET post_content = $postContent WHERE id = $post_id;
COMMIT;
Примечание. Первый оператор INSERT
гарантирует правильную обработку условия гонки на таблице url_references
при условии, что вы включили правильный уровень изоляции транзакции и autocommit=off
.
Примечание. Использование SELECT ... FOR UPDATE
в этом случае не работает, так как блокирует только существующие строки (и нам нужно заблокировать несуществующую строку, которая вот-вот будет вставлена). Извините, если я запутал вас, пожалуйста, проигнорируйте мой комментарий под вашим вопросом.