Как вы обрабатываете устаревшие данные с несколькими потоками? - PullRequest
0 голосов
/ 20 декабря 2018

Допустим, у меня есть следующий psuedocode:

SELECT count(*) FROM users WHERE email = 'bob@gmail.com'
>>>> MARKER A
if (count > 0) return;
else INSERT INTO users VALUES ('bob@gmail.com')

Так что, по сути, вставьте письмо, только если оно еще не существует.Я понимаю, что, возможно, есть какой-то запрос INSERT IF NOT EXISTS, который я мог бы использовать, но, скажем, мы используем этот пример.

Так что, если приведенный выше код выполняется в потоке A, а поток B фактически вставляет 'bob @ gmail.com 'к пользователям на MARKER A, затем поток A имеет «устаревшие данные» и попытается вставить «bob@gmail.com», думая, что счетчик по-прежнему равен 0, но на самом деле это теперь 1. Это приведет к ошибке, так как мыимеют уникальный индекс в электронном письме.

Какой инструмент я должен использовать, чтобы предотвратить эту проблему? Из моего прочтения о транзакциях они в основном делают набор операций атомарным, поэтому кодвыше будет выполнено полностью или не выполнено вообще.Это НЕ гарантирует, что таблица пользователей заблокирована от обновлений правильно?Поэтому я не могу просто обернуть приведенный выше код в транзакцию и сделать его поточно-ориентированным?

Должен ли я реализовать блокировку на уровне приложения?Должен ли я гарантировать, что при выполнении этой операции она должна получить блокировку для доступа к таблице пользователей, чтобы никакой другой поток не мог внести в нее изменения?Я чувствую, что блокировка всей таблицы - это снижение производительности, которого я хочу избежать.

1 Ответ

0 голосов
/ 20 декабря 2018

Проверка перед вставкой является известным анти-паттерном в многопоточных приложениях.Даже не пытайтесь.

Правильный способ сделать это - позволить базе данных позаботиться об этом.Добавьте ограничение UNIQUE на столбец, например:

alter table users add constraint uq1 unique(email);

Просто попробуйте вставить строку в базу данных.Если это удается, все хорошо;если это не удается, тогда какой-то другой поток уже вставил строку.

В качестве альтернативы, вы можете выполнить LOCK для всей таблицы.Это также будет работать, но производительность вашего приложения станет ужасной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...