Уровни изоляции транзакций
От: andyag  
Дата: 25.01.15 19:46
Оценка: 3 (2)
Помогите пожалуйста правильно проинтерпретировать уровни изоляции транзакций. Интересует общее понимание концепции безотносительно конкретных СУБД.

Вопрос номер 1: правильно ли я понимаю, что от СУБД к СУБД нюансы поведения могут отличаться, но несмотря на это, если СУБД заявляет "умею транзакции", есть минимальный набор гарантий, которые обязаны выполняться?

В нескольких источниках, которые я прочитал, уровни изоляции описываются через гарантии по поводу операций чтения. Причём разделяют:
1. Dirty reads — ситуация, когда транзакция видит незакоммиченные изменения в какой-то строке таблицы.
2. Non-repeatable reads — ситуация, когда несколько итераций чтения строки могут приводить к очень разным результатам.
3. Phantom reads — ситуация, когда один и тот же запрос выполненный несколько раз может вернуть очень разные наборы строк.

Я правильно понимаю, что dirty reads и non-repeatable reads действительно относятся только к изменениям на уровне строк, а phantom reads — только к изменениям на уровне таблицы? Т.е. параллельный update может вызвать 1 и 2, но не 3, а параллельный insert/delete — только 3, но не 1 или 2?

Теперь про сами уровни изоляции:

1. Уровень изоляции read uncommitted предполагает, что могут произойти все 3 описанные выше ситуации: 1, 2 и 3. Т.е.:
а. Можно увидеть незакоммиченные изменения в полях
б. Значения полей могут отличаться при нескольких чтениях
в. Выборки строк по критерию могу возвращать разные результаты

2. Уровень изоляции read committed предполагает, что могут произойти только ситуации 2 и 3. Т.е.:
а. Нельзя увидеть незакоммиченные изменения в полях
б. Значения полей могут отличаться при нескольких чтениях
в. Выборки строк по критерию могу возвращать разные результаты

3. Уровень изоляции repeatable read предполагает, что может произойти только ситуация 3.
а. Нельзя увидеть незакоммиченные изменения в полях
б. Значения полей при нескольких чтения будут оставаться неизменными
в. Выборки строк по критерию могу возвращать разные результаты

4. Уровень изоляции serializable предполагает, что ни одной из 3 ситуаций произойти не может.
а. Нельзя увидеть незакоммиченные изменения в полях
б. Значения полей при нескольких чтения будут оставаться неизменными
в. Выборки строк по критерию возвращают одни и те же результаты

Насколько верно? Правильно ли я понимаю, что теоретически СУБД может реализовать только уровень serializable и подставлять его вместо всех менее строгих, т.к. serializable их в себя включает?
Re: Уровни изоляции транзакций
От: Olaf Россия  
Дата: 26.01.15 11:06
Оценка: 2 (1) +1
Здравствуйте, andyag, Вы писали:

A>Вопрос номер 1: правильно ли я понимаю, что от СУБД к СУБД нюансы поведения могут отличаться, но несмотря на это, если СУБД заявляет "умею транзакции", есть минимальный набор гарантий, которые обязаны выполняться?

То что вы перечислили входит в стандарт ISO. По идее многие производители СУБД стремятся к нему, но не всегда поддерживают на 100%, поэтому не исключаю, что могут быть нюансы.

A>Я правильно понимаю, что dirty reads и non-repeatable reads действительно относятся только к изменениям на уровне строк, а phantom reads — только к изменениям на уровне таблицы? Т.е. параллельный update может вызвать 1 и 2, но не 3, а параллельный insert/delete — только 3, но не 1 или 2?


Мне кажется, что здесь привязка к объектам строка-таблица не очень уместна. Например, грязное чтение вы можете получить, не только на обновлении, но и на вставке и удалении, т.е. когда DML изменения не зафиксированы в другой транзакции.

A>Теперь про сами уровни изоляции:

A>...
A>Насколько верно? Правильно ли я понимаю, что теоретически СУБД может реализовать только уровень serializable и подставлять его вместо всех менее строгих, т.к. serializable их в себя включает?

Все написано верно. В теории уровень изоляции serializable покрывает все проблемы описанные вами, но за это приходится расплачиваться снижением уровня конкуренции в БД. Вообще на практике уровень изоляции выбирается из тех задач, которые он помогает решить, а не наоборот. Кроме того в рамках одной БД могут использоваться разные уровни изоляции, опять же в зависимости от задачи. Чтобы со всем этим разобраться мне кажется, нужно взять «любимую СУБД» и рассмотреть реализацию каждого уровня изоляции. Тогда возникнет понимание, а за счет чего именно удается реализовать конкретное поведение (грязное чтение, фантомы и прочее).
Re[2]: Уровни изоляции транзакций
От: andyag  
Дата: 26.01.15 12:31
Оценка:
Здравствуйте, Olaf, Вы писали:

O>Здравствуйте, andyag, Вы писали:


A>>Я правильно понимаю, что dirty reads и non-repeatable reads действительно относятся только к изменениям на уровне строк, а phantom reads — только к изменениям на уровне таблицы? Т.е. параллельный update может вызвать 1 и 2, но не 3, а параллельный insert/delete — только 3, но не 1 или 2?


O>Мне кажется, что здесь привязка к объектам строка-таблица не очень уместна. Например, грязное чтение вы можете получить, не только на обновлении, но и на вставке и удалении, т.е. когда DML изменения не зафиксированы в другой транзакции.


Вот это интересно. А как тогда однозначно разделить non-repeatable reads и phantom reads?

A>>Теперь про сами уровни изоляции:

A>>...
A>>Насколько верно? Правильно ли я понимаю, что теоретически СУБД может реализовать только уровень serializable и подставлять его вместо всех менее строгих, т.к. serializable их в себя включает?

O>Все написано верно. В теории уровень изоляции serializable покрывает все проблемы описанные вами, но за это приходится расплачиваться снижением уровня конкуренции в БД. Вообще на практике уровень изоляции выбирается из тех задач, которые он помогает решить, а не наоборот. Кроме того в рамках одной БД могут использоваться разные уровни изоляции, опять же в зависимости от задачи. Чтобы со всем этим разобраться мне кажется, нужно взять «любимую СУБД» и рассмотреть реализацию каждого уровня изоляции. Тогда возникнет понимание, а за счет чего именно удается реализовать конкретное поведение (грязное чтение, фантомы и прочее).


Я так и поступаю, просто любимая СУБД оказалась неадекватом в плане изоляции — А помогите пожалуйста с транзакциями в JDBC. Вот теперь хочу уточнить кто из нас двоих неадекват.
Отредактировано 26.01.2015 12:32 andyag . Предыдущая версия .
Re[3]: Уровни изоляции транзакций
От: Olaf Россия  
Дата: 26.01.15 16:08
Оценка: 2 (1)
Здравствуйте, andyag, Вы писали:

O>>Мне кажется, что здесь привязка к объектам строка-таблица не очень уместна. Например, грязное чтение вы можете получить, не только на обновлении, но и на вставке и удалении, т.е. когда DML изменения не зафиксированы в другой транзакции.


A>Вот это интересно. А как тогда однозначно разделить non-repeatable reads и phantom reads?


Вообще говоря неповторяющееся чтение возникает в случае если в рамках одной транзакции один и тот же запрос возвращает различные результаты (значения). Происходить это может в двух случаях:
1. Данные изменились, т.е. было выполнено обновление/удаление — неповторяющееся чтение
2. Данные были вставлены, т.е. появились новые записи — фантомное чтение

A>Я так и поступаю, просто любимая СУБД оказалась неадекватом в плане изоляции — А помогите пожалуйста с транзакциями в JDBC. Вот теперь хочу уточнить кто из нас двоих неадекват.


В Java я не специалист, поэтому возможно скажу глупость. Если предположить, что передо мной стоит задача решить описанную вами проблему, то первым делом я проверил бы, а не возвращает ли вот этот код
try(Connection connectionB = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD))

открытое ранее соединение connectionA ? Потому что если это так, то описанная вами ситуация вполне попадает под этот сценарий. Создается вложенная транзакция, которая видит изменения в родительской транзакции.
Re[4]: Уровни изоляции транзакций
От: andyag  
Дата: 26.01.15 21:16
Оценка:
Здравствуйте, Olaf, Вы писали:

O>Здравствуйте, andyag, Вы писали:


A>>Я так и поступаю, просто любимая СУБД оказалась неадекватом в плане изоляции — А помогите пожалуйста с транзакциями в JDBC. Вот теперь хочу уточнить кто из нас двоих неадекват.


O>В Java я не специалист, поэтому возможно скажу глупость. Если предположить, что передо мной стоит задача решить описанную вами проблему, то первым делом я проверил бы, а не возвращает ли вот этот код

O>
O>try(Connection connectionB = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD))
O>

O>открытое ранее соединение connectionA ? Потому что если это так, то описанная вами ситуация вполне попадает под этот сценарий. Создается вложенная транзакция, которая видит изменения в родительской транзакции.

Это всё проверено и перепроверено Для HSQLDB выяснилось, что адекватно он работает только если каждое соединение живёт в своём потоке. И то — не до конца адекватно. У аналога HSQLDB — H2 ситуация немного лучше, отдельные потоки не нужны и даже read_committed/read_uncommitted работают ожидаемо, но вот serializable вызывает кучу вопросов. При этом H2 уже по-честному пишет лог происходящего, рассказывает, что подключения разные, транзакции разные, и т.д. Ничего не скрывая позволяет phantom reads, честно говорит, что никаких локов нету где ожидается. Поэтому я и полез в матчасть
Re[5]: Уровни изоляции транзакций
От: Olaf Россия  
Дата: 27.01.15 05:21
Оценка:
Здравствуйте, andyag, Вы писали:

A>Это всё проверено и перепроверено Для HSQLDB выяснилось, что адекватно он работает только если каждое соединение живёт в своём потоке. И то — не до конца адекватно. У аналога HSQLDB — H2 ситуация немного лучше, отдельные потоки не нужны и даже read_committed/read_uncommitted работают ожидаемо, но вот serializable вызывает кучу вопросов. При этом H2 уже по-честному пишет лог происходящего, рассказывает, что подключения разные, транзакции разные, и т.д. Ничего не скрывая позволяет phantom reads, честно говорит, что никаких локов нету где ожидается. Поэтому я и полез в матчасть


Ситуация более чем странная. Ведь в документации написано, что все должно быть в порядке…

In the new implementation, all isolation levels avoid the "dirty read" phenomenon and do not read uncommitted changes made to rows by other transactions.

Re[6]: Уровни изоляции транзакций
От: andyag  
Дата: 27.01.15 06:30
Оценка:
Здравствуйте, Olaf, Вы писали:

O>Здравствуйте, andyag, Вы писали:


A>>Это всё проверено и перепроверено Для HSQLDB выяснилось, что адекватно он работает только если каждое соединение живёт в своём потоке. И то — не до конца адекватно. У аналога HSQLDB — H2 ситуация немного лучше, отдельные потоки не нужны и даже read_committed/read_uncommitted работают ожидаемо, но вот serializable вызывает кучу вопросов. При этом H2 уже по-честному пишет лог происходящего, рассказывает, что подключения разные, транзакции разные, и т.д. Ничего не скрывая позволяет phantom reads, честно говорит, что никаких локов нету где ожидается. Поэтому я и полез в матчасть


O>Ситуация более чем странная. Ведь в документации написано, что все должно быть в порядке…

O>

O>In the new implementation, all isolation levels avoid the "dirty read" phenomenon and do not read uncommitted changes made to rows by other transactions.


Из последних достижений (на самой свежей версии H2):
try(Connection c1 = DriverManager.getConnection(...)) {
    c1.setAutoCommit(false);

    try(Connection c2 = DriverManager.getConnection(...)) {
        c2.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
        c2.setAutoCommit(false);

        assertEquals(0, selectAll(c1));
        assertEquals(0, selectAll(c2));

        insertOne(c1);

        assertEquals(1, selectAll(c1));
        assertEquals(0, selectAll(c2));

        c1.commit();

        assertEquals(1, selectAll(c1));
        assertEquals(0, selectAll(c2)); // вот тут оказывается не 0, а 1
    }
}

Может быть, поведение отличается в зависимости от того, как именно запущен сервер. В моём случае случае это самый простой in-proc вариант. Намерен попробовать ещё "встроенный полноценный", который может принимать подключения снаружи. HSQLDB тоже умеет эти 2 варианта, но оба ведут себя одинаково.
Re: Уровни изоляции транзакций
От: IB Австрия http://rsdn.ru
Дата: 27.01.15 16:03
Оценка: 2 (1)
Здравствуйте, andyag, Вы писали:

A>Вопрос номер 1: правильно ли я понимаю, что от СУБД к СУБД нюансы поведения могут отличаться, но несмотря на это, если СУБД заявляет "умею транзакции", есть минимальный набор гарантий, которые обязаны выполняться?

В целом — да, но есть особенности реализации от которых зависит, как именно будут выполняться эти гарантии.

A>В нескольких источниках, которые я прочитал, уровни изоляции описываются через гарантии по поводу операций чтения.

В стандарте принято вводить уровни изоляции через феномены (аномалии) — несогласованное состояние возникающее в результате конкурентного доступа (не обязательно чтения). Каждый уровень изоляции не допускает определенный набор феноменов, и каждый последующий уровень включает в себя предыдущий.
За исключением уровня изоляции Serializable, который по определению не допускает никаких феноменов, даже тех, которых еще не придумали.
Строго говоря, определение через феномены довольно неудачное, так как возможный набор феноменов сильно зависят от конкретной реализации алгоритма конкурентного доступа, например "косая запись" (write skew) возможна только при версионном алгоритме, в то же вермя версионный Read Committed строже блокировочного.
Более того, определения уровней изоляции в стандарте даны исходя из блокировочной реализации конкурентного доступа, что вносит дополнительную путаницу и не дает альтернативным решениям строго соответствовать стандарту.

A> Причём разделяют:

A>1. Dirty reads — ситуация, когда транзакция видит незакоммиченные изменения в какой-то строке таблицы.
A>2. Non-repeatable reads — ситуация, когда несколько итераций чтения строки могут приводить к очень разным результатам.
A>3. Phantom reads — ситуация, когда один и тот же запрос выполненный несколько раз может вернуть очень разные наборы строк.
На самом деле, различают гораздо больше.
Для лучшего понимания, рекомендую классическую статью с критикой уровня изоляций стандарта A Critique of ANSI SQL Isolation Levels


A>Я правильно понимаю, что dirty reads и non-repeatable reads действительно относятся только к изменениям на уровне строк, а phantom reads — только к изменениям на уровне таблицы?

Нет. Теоретически, рассогласование может быть даже между индексом и таблицей.


A>Правильно ли я понимаю, что теоретически СУБД может реализовать только уровень serializable и подставлять его вместо всех менее строгих, т.к. serializable их в себя включает?

Да, как я писал выше, определение уровня изоляции Serializable, в отличии от всех остальных, дается не через феномены, а через критерий сериализуемости. То есть, условием уровня изоляции serizlizable является то, что результат выполнения параллельных транзакций должен быть таким, как буд-то бы транзакции выполнялись последовательно, в любом порядке. А что не допускает появления никаких феноменов (аномалий) по определению.
Мы уже победили, просто это еще не так заметно...
Re: Уровни изоляции транзакций
От: MasterZiv СССР  
Дата: 28.01.15 12:05
Оценка:
Здравствуйте, andyag, Вы писали:

A>Помогите пожалуйста правильно проинтерпретировать уровни изоляции транзакций. Интересует общее понимание концепции безотносительно конкретных СУБД.


Для этого рекомендую потратить время и изучить статью

http://citforum.ru/database/classics/SQL_critiques/
(лучше найти в виде PDF, и на английском, там вроде бы ещё картинки были)

Оно того стоит, и будешь знать изоляции от и до, "на зубок".


A>Вопрос номер 1: правильно ли я понимаю, что от СУБД к СУБД нюансы поведения могут отличаться, но несмотря на это, если СУБД заявляет "умею транзакции", есть минимальный набор гарантий, которые обязаны выполняться?


И да, и нет. Нюансы поведения будут различными, однако требования, налагаемые стандартом ANSI почти всегда соблюдаются (но от этого, поверь, не легче).


A>В нескольких источниках, которые я прочитал, уровни изоляции описываются через гарантии по поводу операций чтения. Причём разделяют:

A>1. Dirty reads — ситуация, когда транзакция видит незакоммиченные изменения в какой-то строке таблицы.
A>2. Non-repeatable reads — ситуация, когда несколько итераций чтения строки могут приводить к очень разным результатам.
A>3. Phantom reads — ситуация, когда один и тот же запрос выполненный несколько раз может вернуть очень разные наборы строк.

Да, это т.н. "феномены" (по латыни -- явления).
Так изоляцию описывают в ANSI SQL -- стандарте языка SQL.


A>Я правильно понимаю, что dirty reads и non-repeatable reads действительно относятся только к изменениям на уровне строк, а phantom reads — только к изменениям на уровне таблицы? Т.е. параллельный update может вызвать 1 и 2, но не 3, а параллельный insert/delete — только 3, но не 1 или 2?



Неправильно. Все изменения -- на уровне строк. Не бывает изменений на уровне таблицы.
Мысли про параллельные insert/update вообще неверны в принципе -- update ничем не отличается от delete + insert, т.е. по одному эффекту своему (появление новых строк данных) от insert.
Т.е. это вообще одно и то же с точки зрения изоляции транзакций.



A>Теперь про сами уровни изоляции:


A>1. Уровень изоляции read uncommitted предполагает, что могут произойти все 3 описанные выше ситуации: 1, 2 и 3. Т.е.:

A>а. Можно увидеть незакоммиченные изменения в полях
A>б. Значения полей могут отличаться при нескольких чтениях
A>в. Выборки строк по критерию могу возвращать разные результаты

A>2. Уровень изоляции read committed предполагает, что могут произойти только ситуации 2 и 3. Т.е.:

A>а. Нельзя увидеть незакоммиченные изменения в полях
A>б. Значения полей могут отличаться при нескольких чтениях
A>в. Выборки строк по критерию могу возвращать разные результаты

A>3. Уровень изоляции repeatable read предполагает, что может произойти только ситуация 3.

A>а. Нельзя увидеть незакоммиченные изменения в полях
A>б. Значения полей при нескольких чтения будут оставаться неизменными
A>в. Выборки строк по критерию могу возвращать разные результаты

A>4. Уровень изоляции serializable предполагает, что ни одной из 3 ситуаций произойти не может.

A>а. Нельзя увидеть незакоммиченные изменения в полях
A>б. Значения полей при нескольких чтения будут оставаться неизменными
A>в. Выборки строк по критерию возвращают одни и те же результаты

A>Насколько верно?


Всё верно, кроме одного -- serializable предполагает явно устранение также всех других известных и неизвестных науке аномалий чтения и модификации данных.
Например, есть известная уже аномалия write skew, которая должна убираться на режиме serializable.

A> Правильно ли я понимаю, что теоретически СУБД может реализовать только уровень serializable и подставлять его вместо всех менее строгих, т.к. serializable их в себя включает?


Да, но это бы означало, грубо говоря, монопольную работу каждого пользователя с БД поочереди.
Поэтому в реальности никто так не делает.
Re[3]: Уровни изоляции транзакций
От: MasterZiv СССР  
Дата: 28.01.15 12:09
Оценка:
Здравствуйте, andyag, Вы писали:

A>Я так и поступаю, просто любимая СУБД оказалась неадекватом в плане изоляции — А помогите пожалуйста с транзакциями в JDBC. Вот теперь хочу уточнить кто из нас двоих неадекват.


Ты уверен, что эта HSQLDB поддерживает ANSI-транзакции ?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.