Транзакции MySQL: несколько одновременных транзакций и целостность данных

Я использую транзакции для управления данными в нескольких таблицах MySQL InnoDB в достаточно сложном веб-приложении. Вкратце, данная транзакция работает следующим образом:

  1. Data is read from a row in a "user_point_totals" table
  2. Various machinations calculate what the user's new point total should be
  3. A new entry is created in the "user_point_totals" table reflecting the updated total

Предположим, что пользователь A выполняет какое-то действие, имеющее разветвления, связанные с баллами, выполняется шаг 1, этот поток выполнения считывает общее количество баллов пользователя в память, и приложение начинает вычислять новую сумму. Тем временем пользователь B выполняет действие, которое влияет на общее количество баллов пользователя A, и начинается другая транзакция; однако первая транзакция еще не завершена, поэтому второй поток получает то же общее значение баллов в качестве начальной точки, что и первая транзакция (из той же строки таблицы). Впоследствии транзакция 1 завершается и создает новую общую сумму баллов пользователя с учетом того, каким должно быть новое значение, а вскоре после этого завершается транзакция 2 и также создает новую строку для общей суммы баллов пользователя. Однако общая сумма баллов второй транзакции теперь неверна, так как не учитывает новую общую сумму, созданную транзакцией 1.

Мои вопросы:

  • Is this scenario impossible due to the atomic nature of transactions, which I apparently don't understand as well as I should?
  • If not, how does one ensure that data integrity exists in these sorts of situations?

Спасибо за внимание!


person justinbach    schedule 22.09.2010    source источник


Ответы (1)


На техническом уровне вы можете использовать блокировку таблицы (или блокировки строк) возможности MySQL. Это позволит вам определить, действительно ли кто-то что-то вычисляет, используя таблицу. С другой стороны, этот метод потребует многих соображений, например, что произойдет, если произойдет сбой процесса и т. д.

Однако на практическом уровне я сомневаюсь, что вы захотите сделать что-то подобное. Такие операторы, как sum() или avg() в MySQL, уже оптимизированы для этой цели. Если вам нужно суммировать некоторые столбцы таблицы и получить ответ в таблице, вы можете использовать представление или создать временную таблицу (возможно, но медленнее). У вас не должно быть столбца, содержащего значение, которое можно вычислить из других столбцов. Эта ситуация приводит к несоответствиям, поскольку неясно, какое поле истинно, если отношение не уравновешено. (Это ошибка сценария ввода или преднамеренное повторное использование поля каким-то программистом?)

Во-вторых, обязательно используйте таблицы InnoDB в своем экземпляре MySQL, иначе ваша система не будет полностью совместима с ACID, а это означает, что вы не получите необходимую атомарность.

person Soravux    schedule 22.09.2010
comment
Вы можете найти информацию о просмотрах на этой странице: dev.mysql.com/ технические ресурсы/статьи/mysql-views.html - person Soravux; 22.09.2010
comment
к сожалению ссылка битая - person Sergey Orshanskiy; 10.10.2013
comment
Сеть, безусловно, движущаяся вещь! :) Возможно, вам лучше не искать представления в вашей любимой поисковой системе... Использование для 5.5 можно найти здесь: dev.mysql.com/doc/refman/5.5/en/view-syntax.html - person Soravux; 10.10.2013