Уровень изоляции транзакции: установить уровень изоляции таблицы по-разному
Если я установлю уровень изоляции транзакции в READ_COMMITTED, могу ли я установить уровень изоляции таблицы по-другому, например, READ_UNCOMMITTED? Причина этого заключается в том, что изменения в таблице должны быть сразу видны другим транзакциям.
Transaction: READ_COMMITTED
Table Foo: READ_UNCOMMITTED
Например, генератор идентификаторов таблицы JPA
Entity Type Next Id
----------------------------------
EMP 100
DEPT 5
Когда одна транзакция получает новый идентификатор сотрудника, увеличьте его идентификатор до 101. Этот новый идентификатор должен быть сразу же виден другим транзакциям. В противном случае это приведет к дублированию идентификатора.
Предположим, что уровни изоляции всех транзакций READ_COMMITTED. Как сделать изменения в таблице видимыми для других транзакций до совершения текущей транзакции?
Как насчет Mysql, Oracle db, SqlServer?
1 ответ
Этот новый идентификатор должен быть виден другим транзакциям немедленно. В противном случае это приведет к дублированию идентификатора.
Использование READ_UNCOMMITTED не решит вашу проблему.
Предположим, ваша транзакция прочитала последнее значение id, а затем пытается использовать id+1. Но между моментами считывания последнего идентификатора и попытки использовать следующее значение какая-то третья транзакция использовала это значение, и тогда у вас все еще появляется повторяющаяся ошибка.
Это называется условием гонки, и даже если вы используете READ_UNCOMMITTED, вы не сможете решить его быстро.
Кроме того, плохая идея использовать READ_UNCOMMITTED в любой базе данных. Что если другая транзакция по какой-то причине откатывается? Ваша транзакция будет считывать данные, которые никогда не будут "существовать" в том смысле, что они никогда не были зафиксированы.
Именно по этой причине все бренды СУБД имеют возможность генерировать значения идентификаторов вне области транзакции.
- MySQL: AUTO_INCREMENT
- Оракул: ПОСЛЕДОВАТЕЛЬНОСТЬ
- Microsoft SQL Server: IDENTITY
Общим для каждой из этих реализаций является то, что база данных может генерировать новые значения идентификатора в некой глобальной области видимости, так что две параллельные транзакции гарантированно не будут генерировать одно и то же значение.
Вы должны использовать механизм для генерации уникальных значений идентификаторов, а не зависеть от SELECT id+1...
решение. SELECT
подлежит изоляции транзакции, поэтому он не может увидеть последнее сгенерированное значение идентификатора, зафиксированный или нет. Но база данных знает, и она никогда не вернет одно и то же значение двум различным транзакциям.
К сожалению, синтаксис каждой из этих реализаций различен, поэтому сложно написать код SQL, который работает одинаково для всех типов баз данных SQL.