Как обеспечить согласованность данных в этой параллельной ситуации? - PullRequest
2 голосов
/ 12 марта 2010

Проблема заключается в следующем:

  • У меня есть несколько конкурирующих потоков (более 100), которым требуется доступ к одной таблице базы данных
  • Каждый поток будет передавать String name - там, где это имя существует в таблице, база данных должна вернуть идентификатор строки, где имя еще не существует, имя должно быть вставлено, а идентификатор возвращен.
  • В базе данных может быть только один экземпляр name, т.е. имя должно быть уникальным

Как сделать так, чтобы поток 1 не вставлял name1 одновременно с тем, как поток 2 также пытается вставить name1? Другими словами, как я могу гарантировать уникальность name в параллельной среде? Это также должно быть максимально эффективным - это может стать серьезным узким местом.

Я использую MySQL и Java.

Спасибо

Ответы [ 3 ]

7 голосов
/ 12 марта 2010

Если для столбца имени существует уникальное ограничение, каждый insert получает блокировку. Любой поток, который попытается вставить его во второй раз одновременно, будет ожидать, пока 1-й insert не будет выполнен успешно или завершится неудачно (передача или откат tx).

Если 1-я транзакция прошла успешно, 2-я транзакция завершится с ошибкой уникального ключа. Тогда вы знаете, что оно уже существует.

Если в транзакции есть одна вставка, то это ок. Если в транзакции используется более 1 вставки, вы можете зайти в тупик.

Каждый поток передаст имя строки - где это имя существует в таблице, база данных должна вернуть идентификатор для строка, где имя не уже существует, имя должно быть вставлен и идентификатор возвращен.

В общем, алгоритм такой:

1 read row with name
   2.1 if found, return row id
   2.2 if not found, attempt to insert
      2.2.1 if insert succeeds, return new row id
      2.2.2 if insert fails with unique constraint violation
          2.2.2.1 read row with name
          2.2.2.2 read should succeed this time, so return row id

Поскольку в уникальном индексе может быть высокая конкуренция , insert может блокироваться в течение некоторого времени. В этом случае транзакция может истечь . Проведите стресс-тест и настройте конфигурацию, пока она не будет корректно работать с вашей нагрузкой.

Кроме того, вы должны проверить, если вы получаете уникальное нарушение ограничения исключение или какое-либо другое исключение.

И снова, это работает, только если в транзакции есть одна вставка, в противном случае может тупик .


Кроме того, вы можете попробовать прочитать строку на шаге 1 с помощью «select * for update». В этом случае он ожидает, пока одновременная вставка не завершится или не завершится успешно. Это может немного уменьшить количество ошибок на шаге 2.2.2 из-за конфликта в индексе.

3 голосов
/ 12 марта 2010

Создать уникальное ограничение для столбца имени в базе данных.

2 голосов
/ 12 марта 2010

Добавить уникальное ограничение для столбца имени.

...