<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Роман Калинин</title><author><name>Роман Калинин</name></author><id>https://teletype.in/atom/north69</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/north69?offset=0"></link><link rel="alternate" type="text/html" href="https://teletype.in/@north69?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=north69"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/north69?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-04-03T17:24:36.381Z</updated><entry><id>north69:transaction-isolation-levels</id><link rel="alternate" type="text/html" href="https://teletype.in/@north69/transaction-isolation-levels?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=north69"></link><title>Уровни изоляции транзакций</title><published>2022-12-29T11:38:21.293Z</published><updated>2023-11-26T15:05:36.587Z</updated><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img3.teletype.in/files/ef/94/ef9401c9-7aed-4cd3-b068-efc9f7b1e247.png"></media:thumbnail><category term="databases" label="databases"></category><summary type="html">Шпаргалка с описанием уровней изоляции транзакций в базах данных</summary><content type="html">
  &lt;h2 id=&quot;mUad&quot;&gt;Проблематика&lt;/h2&gt;
  &lt;p id=&quot;scSQ&quot;&gt;Ниже описаны проблемы при одновременной работе транзакций&lt;/p&gt;
  &lt;h3 id=&quot;7tEZ&quot;&gt;Потерянное обновление (англ. lost update)&lt;/h3&gt;
  &lt;p id=&quot;hnEw&quot;&gt;При одновременном изменении одного блока данных разными транзакциями, одно из изменений теряется.&lt;/p&gt;
  &lt;p id=&quot;5SLY&quot;&gt;Имеются две транзакции, выполняемые одновременно:&lt;/p&gt;
  &lt;pre id=&quot;RLCt&quot; data-lang=&quot;sql&quot;&gt;-- Транзакция 1
UPDATE accounts SET balance=balance+20 WHERE id=1;
-- Транзакция 2
UPDATE accounts SET balance=balance+25 WHERE id=1;&lt;/pre&gt;
  &lt;p id=&quot;v5G6&quot;&gt;В обеих транзакциях изменяется значение поля balance, при этом одно из изменений теряется. Так что, balance будет увеличено не на 45, а только на 20 или 25.&lt;/p&gt;
  &lt;p id=&quot;XC1F&quot;&gt;Причины:&lt;/p&gt;
  &lt;ol id=&quot;JCIX&quot;&gt;
    &lt;li id=&quot;8yw5&quot;&gt;Первая транзакция прочитала текущее состояние поля.&lt;/li&gt;
    &lt;li id=&quot;RyiE&quot;&gt;Вторая транзакция сделала свои изменения, основываясь на своих сохраненных в память данных.&lt;/li&gt;
    &lt;li id=&quot;YEs4&quot;&gt;Первая делает обновление поля, используя свои «старые» данные.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;h4 id=&quot;Jai4&quot;&gt;&lt;strong&gt;«Грязное» чтение&lt;/strong&gt; (англ. dirty read)&lt;/h4&gt;
  &lt;p id=&quot;NYje&quot;&gt;Чтение данных в одной транзакции, добавленных или изменённых другой транзакцией, которая впоследствии не зафиксируется (ROLLBACK);&lt;/p&gt;
  &lt;pre id=&quot;T1qG&quot; data-lang=&quot;sql&quot;&gt;-- Транзакция 1                   -- Транзакция 2
SELECT f FROM tbl1 WHERE id=1;
UPDATE tbl1 SET f=f+1 WHERE id=1;
                                  SELECT f FROM tbl1 WHERE id=1;
ROLLBACK;&lt;/pre&gt;
  &lt;p id=&quot;mPQ9&quot;&gt;В транзакции 1 изменяется значение поля f, а затем в транзакции 2 выбирается значение этого поля. После этого происходит откат транзакции 1. В результате значение, полученное второй транзакцией, будет отличаться от значения, хранимого в базе данных.&lt;/p&gt;
  &lt;h4 id=&quot;2Gk5&quot;&gt;&lt;strong&gt;Неповторяющееся чтение&lt;/strong&gt; (англ. non-repeatable read)&lt;/h4&gt;
  &lt;p id=&quot;mHKc&quot;&gt;При повторном чтении в рамках одной транзакции, ранее прочитанные данные оказываются изменёнными.&lt;/p&gt;
  &lt;p id=&quot;4kVz&quot;&gt;Предположим, имеются две транзакции, открытые в разных сессиях, в которых выполнены следующие запросы:&lt;/p&gt;
  &lt;pre id=&quot;yRda&quot; data-lang=&quot;sql&quot;&gt;-- Транзакция 1	                  -- Транзакция 2
SELECT f FROM tbl1 WHERE id=1;	  SELECT f FROM tbl1 WHERE id=1;
UPDATE tbl1 SET f=f+1 WHERE id=1;
COMMIT;
                                  SELECT f FROM tbl1 WHERE id=1;&lt;/pre&gt;
  &lt;p id=&quot;qZjQ&quot;&gt;В транзакции 2 выбирается значение поля f, затем в транзакции 1 изменяется значение поля f. При повторной попытке выбора значения из поля f в транзакции 2 будет получен другой результат. Эта ситуация особенно неприемлема, когда данные считываются с целью их частичного изменения и обратной записи в базу данных.&lt;/p&gt;
  &lt;h4 id=&quot;W2dx&quot;&gt;&lt;strong&gt;Фантомное чтение (англ. phantom reads)&lt;/strong&gt;&lt;/h4&gt;
  &lt;p id=&quot;Cngh&quot;&gt;Одна транзакция в ходе своего выполнения несколько раз выбирает множество строк по одним и тем же критериям. Другая транзакция в интервалах между этими выборками добавляет или удаляет строки или изменяет столбцы некоторых строк, используемых в критериях выборки первой транзакции, и успешно заканчивается. В результате получится, что одни и те же выборки в первой транзакции дают разные множества строк.&lt;/p&gt;
  &lt;pre id=&quot;9gQc&quot; data-lang=&quot;sql&quot;&gt;-- Транзакция 1	                         -- Транзакция 2
                                         SELECT SUM(f2) FROM tbl1;
INSERT INTO tbl1 (f1,f2) VALUES (15,20);
COMMIT;
                                         SELECT SUM(f2) FROM tbl1;                                         &lt;/pre&gt;
  &lt;p id=&quot;CFJ7&quot;&gt;В транзакции 2 получаем суму всех значений в колонке f2. Затем в транзакции 1 выполняется вставка новой строки, приводящая к тому, что повторное выполнение запроса в транзакции 2 выдаст другой результат. Такая ситуация называется фантомным чтением. От неповторяющегося чтения оно отличается тем, что результат повторного обращения к данным изменился не из-за изменения/удаления самих этих данных, а из-за появления новых (фантомных) данных.&lt;/p&gt;
  &lt;h2 id=&quot;5Xk2&quot;&gt;Уровни изоляции&lt;/h2&gt;
  &lt;h3 id=&quot;6joi&quot;&gt;&lt;strong&gt;Read uncommitted (чтение незафиксированных данных)&lt;/strong&gt;&lt;/h3&gt;
  &lt;p id=&quot;QIHo&quot;&gt;Уровень, имеющий самую плохую согласованность данных, но самую высокую скорость выполнения транзакций. Название уровня говорит само за себя — каждая транзакция видит незафиксированные изменения другой транзакции (феномен &lt;strong&gt;грязного чтения&lt;/strong&gt;). Этот уровень гарантирует только отсутствие потерянных обновлений.&lt;/p&gt;
  &lt;h3 id=&quot;G5Ij&quot;&gt;&lt;strong&gt;Read committed (чтение фиксированных данных)&lt;/strong&gt;&lt;/h3&gt;
  &lt;p id=&quot;BKFV&quot;&gt;Для этого уровня параллельно исполняющиеся транзакции видят только зафиксированные изменения из других транзакций. Таким образом, данный уровень обеспечивает защиту от &lt;strong&gt;грязного чтения&lt;/strong&gt;. Тем не менее после фиксации данных в одной транзакции и повторном запросе в другой транзакции результат запроса будет другим. Это проблема неповторяемого чтения.&lt;/p&gt;
  &lt;h3 id=&quot;KkYA&quot;&gt;&lt;strong&gt;Repeatable read (повторяемость чтения)&lt;/strong&gt;&lt;/h3&gt;
  &lt;p id=&quot;8wY6&quot;&gt;Уровень, при котором чтение одной и той же строки или строк в транзакции дает одинаковый результат. Даже после фиксации других транзакций. Но мы все еще видим добавленные записи из другой транзакции.&lt;/p&gt;
  &lt;h3 id=&quot;YD0q&quot;&gt;Serializable&lt;/h3&gt;
  &lt;p id=&quot;MmaP&quot;&gt;Изоляция уровня этого уровня обеспечивает беспрепятственный доступ к базе данных транзакциям с SELECT запросами. Но для транзакций с запросами UPDATE и DELETE, этот уровень изоляции не допускает модификации одной и той же строки в рамках разных транзакций. При попытке обновления данных мы получим lock и будем ждать пока не завершится транзакция в которой были запрошены строки которые обновляются в текущей транзакции. Так решается проблема фантомного чтения.&lt;/p&gt;
  &lt;h3 id=&quot;MLMh&quot;&gt;Таблица уровней на которых предотвращаются типы проблем&lt;/h3&gt;
  &lt;pre id=&quot;dRr9&quot;&gt;Уровень изоляции lost update | dirty read | unrepeadable read | phantom read
READ UNCOMMITTED     +              -                -                -
READ COMMITTED       +              +                -                -
REPEATABLE READ      +              +                +                -
SERIALIZABLE         +              +                +                +&lt;/pre&gt;
  &lt;h2 id=&quot;fmNt&quot;&gt;Deadlocks (взаимная блокировка транзакций)&lt;/h2&gt;
  &lt;p id=&quot;ETId&quot;&gt;Первая транзакции блокирует выполнение второй транзакции, а вторая транзакция блокирует выполнение первой транзакции. В этом случае одна из транзакций падает с ошибкой &lt;em&gt;«Deadlock found when trying to get lock; try restarting transaction».&lt;/em&gt;&lt;/p&gt;
  &lt;pre id=&quot;9xGi&quot; data-lang=&quot;sql&quot;&gt;START TRANSACTION;                START TRANSACTION;
                                  /*lock row 1*/
                                  UPDATE tbl1 SET f=f+1 WHERE id=1;
/*lock row 2*/
UPDATE tbl1 SET f=f+2 WHERE id=2;
                                  /*try to lock row 2, waiting*/
                                  UPDATE tbl1 SET f=f-1 WHERE id=2;
/*try to lock row 1, will end a deadlock*/
UPDATE tbl1 SET f=f-2 WHERE id=1;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction&lt;/pre&gt;
  &lt;h2 id=&quot;Imah&quot;&gt;Полезные команды&lt;/h2&gt;
  &lt;p id=&quot;uhlu&quot;&gt;выяснить текущий уровень изоляции&lt;/p&gt;
  &lt;pre id=&quot;TwzP&quot; data-lang=&quot;sql&quot;&gt;SELECT @@GLOBAL.transaction_isolation, @@GLOBAL.transaction_read_only;
SELECT @@SESSION.transaction_isolation, @@SESSION.transaction_read_only;&lt;/pre&gt;
  &lt;p id=&quot;mGNw&quot;&gt;установить уровень изоляции для сессии&lt;/p&gt;
  &lt;pre id=&quot;2dCG&quot; data-lang=&quot;sql&quot;&gt;SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- возможные уровни REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED | SERIALIZABLE&lt;/pre&gt;
  &lt;p id=&quot;osw6&quot;&gt;просмотреть список транзакций которые могли зависнуть&lt;/p&gt;
  &lt;pre id=&quot;ebrc&quot; data-lang=&quot;sql&quot;&gt;SELECT * FROM information_schema.innodb_trx\G;&lt;/pre&gt;
  &lt;h2 id=&quot;tKXI&quot;&gt;Ссылки&lt;/h2&gt;
  &lt;ul id=&quot;5MJK&quot;&gt;
    &lt;li id=&quot;um0A&quot;&gt;&lt;a href=&quot;https://habr.com/ru/post/469415/&quot; target=&quot;_blank&quot;&gt;https://habr.com/ru/post/469415/&lt;/a&gt; базовая статья с примерами&lt;/li&gt;
    &lt;li id=&quot;qA9I&quot;&gt;&lt;a href=&quot;https://medium.com/pseudo-blog/уровни-изоляции-транзакций-87cd2b129de1&quot; target=&quot;_blank&quot;&gt;https://medium.com/pseudo-blog/уровни-изоляции-транзакций-87cd2b129de1&lt;/a&gt;  более подробная статья с исторической справкой вначале&lt;/li&gt;
    &lt;li id=&quot;z9rr&quot;&gt;&lt;a href=&quot;https://shurshun.ru/tranzaktsii-blokirovki-urovni-izoliovannosti-tranzaktsiy-v-mysql/&quot; target=&quot;_blank&quot;&gt;https://shurshun.ru/tranzaktsii-blokirovki-urovni-izoliovannosti-tranzaktsiy-v-mysql/&lt;/a&gt; тут хорошо описана проблематика&lt;/li&gt;
    &lt;li id=&quot;ut6c&quot;&gt;&lt;a href=&quot;https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html&quot; target=&quot;_blank&quot;&gt;https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html&lt;/a&gt; дока mysql&lt;/li&gt;
    &lt;li id=&quot;vQs1&quot;&gt;&lt;a href=&quot;https://habr.com/ru/post/555920/&quot; target=&quot;_blank&quot;&gt;https://habr.com/ru/post/555920/&lt;/a&gt; про ACID для самых маленьких&lt;/li&gt;
    &lt;li id=&quot;egjO&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/2950676/difference-between-set-autocommit-1-and-start-transaction-in-mysql-have-i-misse&quot; target=&quot;_blank&quot;&gt;https://stackoverflow.com/questions/2950676/difference-between-set-autocommit-1-and-start-transaction-in-mysql-have-i-misse&lt;/a&gt; разница между start transaction и set autocommit = 0&lt;/li&gt;
  &lt;/ul&gt;

</content></entry></feed>