В действительности эта проблема существует, и понятно, откуда она берется: необходимо как-то учесть эффекты, связанные с тем, что пока один пользователь читает данные, другой пользователь (или другие пользователи) может эти данные изменять. Стандарт ANSI SQL-92 описывает требования к реализации нескольких т.н. мод изоляции операций чтения от выполняющихся одновременно с ним транзакций. Они варьируют от самой “слабой” моды - т.н. “незафиксированного” (часто называемого “грязным”) чтения, при котором допускается считывание данных незафиксированных транзакций, до самой “сильной” - т.н. “повторяемого” чтения, при которой гарантируется повторяемость результата при повторении операции в рамках транзакции* .Беда вся в том, что само наличие всех этих различных мод изоляции в стандарте SQL отражает отнюдь не потребности пользователей (трудно представить себе, например, разработчика приложения, заинтересованного в чтении данных чужих незафиксированных транзакций - если только он не страдает такой особой формой мазохизма), а различные степени компромисса с возможностями разработчиков СУБД. Пользователей же волнует (или во всяком случае должно волновать) совсем другое: как избежать тех неприятных эффектов, которые могут быть связаны с использованием всех стандартных мод изоляции, кроме самой “сильной” из них. Чтобы не быть голословным, рассмотрим очень простой пример. Допустим, в некоей банковской системе есть таблица, состоящая всего из двух полей:
СЧЕТА
Номер_счета |
Сумма |
1 |
100000 |
2 |
100000 |
3 |
100000 |
. |
. |
. |
. |
. |
. |
99,998 |
100000 |
99,999 |
100000 |
100,000 |
100000 |
Предположим, пользователь запустил операцию подсчета общей суммы денег на всех счетах:
select sum(Сумма) from СЧЕТА;
В любой СУБД такая операция выполняется путем последовательного перебора всех записей таблицы с подсчетом требуемой суммы. Пусть теперь другой пользователь одновременно с выполнением этого отчета (то есть после его начала, но до его завершения) проводит простую транзакцию, переводящую 50000 с одного счета на другой:
update СЧЕТА set Сумма = Сумма - 50000 where Номер_счета = 1; update СЧЕТА set Сумма = Сумма + 50000 where Номер_счета = 100000; commit;