Fork me on GitHub

Уровень изолированности транзакций

В PostgreSQL (в отличии от MySQL и её форков) по умолчанию используется версионность данных. Это означает, что в момент записи данных в поле - всем запросам вне транзакции видна старая версия данных этого поля. В момент коммита транзакции - версия записи становится текущей но старая ещё сохраняется.

  • READ UNCOMMITTED - исходя из названия понятно, что читать будет до того как был коммит транзакции. Ещё это называют dirty read ("грязное чтение")
  • READ COMMTITED - в этом варианте данные можно будет прочитать только после коммита транзакции, причём даже для самой транзакции!
  • REPEATABLE READ - вариант по умолчанию, есть вероятность "фантомного чтения" при двух одновременных транзакциях читающих и пишущих в одно поле.
  • SERIALIZABLE - создаёт блокировку на поле до завершения транзакции (решает проблему "фантомного чтения"). С использованием InnoDB и Falcon нет смысла в этом режиме т.к. архитектура таблицы решает проблему "фантомного чтения".

Примет на MariaDB с настройкой по умолчанию

1
2
CREATE TABLE test (id INT, value VARCHAR(255)) ENGINE=InnoDB;
Query OK, 0 rows affected (0.73 sec)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

INSERT INTO test(id, value) VALUES (1, 'test'), (2, 'test 2');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

SELECT * FROM test;
+------+--------+
| id   | value  |
+------+--------+
|    1 | test   |
|    2 | test 2 |
+------+--------+
2 rows in set (0.00 sec)

COMMIT;
Query OK, 0 rows affected (0.05 sec)

SELECT * FROM test;
+------+--------+
| id   | value  |
+------+--------+
|    1 | test   |
|    2 | test 2 |
+------+--------+
2 rows in set (0.00 sec)

Проверяю какой сейчас и пробую поменять режим

1
2
3
4
5
6
7
SHOW VARIABLES LIKE '%tx_isolation%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
1 row in set (0.00 sec)
1
2
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Query OK, 0 rows affected (0.00 sec)

Смотрю что получилось

1
2
3
4
5
CREATE TABLE one(id INT, value VARCHAR(12)) ENGINE = MyISAM;
Query OK, 0 rows affected (0.19 sec)

CREATE TABLE two(id INT, value VARCHAR(12)) ENGINE = InnoDB;
Query OK, 0 rows affected (0.66 sec)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

INSERT INTO one (id, value) VALUES (1, 'test');
Query OK, 1 row affected (0.01 sec)

INSERT INTO two (id, value) VALUES (1, 'test');
Query OK, 1 row affected (0.00 sec)

ROLLBACK;
Query OK, 0 rows affected, 1 warning (0.07 sec)

SELECT * FROM one;
+------+-------+
| id   | value |
+------+-------+
|    1 | test  |
+------+-------+
1 row in set (0.00 sec)

SELECT * FROM two;
Empty set (0.00 sec)
Уровень изоляции Фантомное чтение Неповторяющееся чтение "Грязное" чтение Потерянное обновление
SERIALIZABLE + + + +
REPEATABLE READ - + + +
READ COMMITTED - - + +
READ UNCOMMITTED - - - +

(+) — предотвращает, (-) — не предотвращает

PS: Всё это есть в документации но до этого момента наверное не дочитывают ;)

Comments