diff --git a/.obsidian/plugins/home-tab/data.json b/.obsidian/plugins/home-tab/data.json index e26197a8..9cddc6d4 100644 --- a/.obsidian/plugins/home-tab/data.json +++ b/.obsidian/plugins/home-tab/data.json @@ -23,25 +23,25 @@ "markdownOnly": false, "unresolvedLinks": false, "recentFilesStore": [ + { + "filepath": "_inbox/Неповторяющееся чтение.md", + "timestamp": 1718817191076 + }, { "filepath": "knowledge/dev/database/Уровни изоляций транзакций БД.md", - "timestamp": 1718816928649 - }, - { - "filepath": "_inbox/Транзакция БД.md", - "timestamp": 1718816827388 - }, - { - "filepath": "knowledge/dev/database/Проблемы при параллельном выполнении нескольких транзакций.md", - "timestamp": 1718816823586 + "timestamp": 1718817183091 }, { "filepath": "_inbox/Потерянное обновление.md", - "timestamp": 1718816800840 + "timestamp": 1718817154181 }, { - "filepath": "_inbox/Race condition.md", - "timestamp": 1718816771915 + "filepath": "_inbox/Repeatable read.md", + "timestamp": 1718817107184 + }, + { + "filepath": "_inbox/Serializable.md", + "timestamp": 1718817019589 } ], "bookmarkedFileStore": [], diff --git a/.obsidian/plugins/recent-files-obsidian/data.json b/.obsidian/plugins/recent-files-obsidian/data.json index 424f350f..939ff0b9 100644 --- a/.obsidian/plugins/recent-files-obsidian/data.json +++ b/.obsidian/plugins/recent-files-obsidian/data.json @@ -1,9 +1,25 @@ { "recentFiles": [ + { + "basename": "Неповторяющееся чтение", + "path": "_inbox/Неповторяющееся чтение.md" + }, { "basename": "Уровни изоляций транзакций БД", "path": "knowledge/dev/database/Уровни изоляций транзакций БД.md" }, + { + "basename": "Потерянное обновление", + "path": "_inbox/Потерянное обновление.md" + }, + { + "basename": "Repeatable read", + "path": "_inbox/Repeatable read.md" + }, + { + "basename": "Serializable", + "path": "_inbox/Serializable.md" + }, { "basename": "Транзакция БД", "path": "_inbox/Транзакция БД.md" @@ -12,10 +28,6 @@ "basename": "Проблемы при параллельном выполнении нескольких транзакций", "path": "knowledge/dev/database/Проблемы при параллельном выполнении нескольких транзакций.md" }, - { - "basename": "Потерянное обновление", - "path": "_inbox/Потерянное обновление.md" - }, { "basename": "Race condition", "path": "_inbox/Race condition.md" @@ -24,10 +36,6 @@ "basename": "Безмастерная репликация", "path": "_inbox/Безмастерная репликация.md" }, - { - "basename": "Неповторяющееся чтение", - "path": "_inbox/Неповторяющееся чтение.md" - }, { "basename": "Фантомное чтение", "path": "_inbox/Фантомное чтение.md" @@ -191,14 +199,6 @@ { "basename": "Вопросы работодателю", "path": "notes/Собеседования/Вопросы работодателю.md" - }, - { - "basename": "Улучшение производительности отдельного сервиса", - "path": "_inbox/Улучшение производительности отдельного сервиса.md" - }, - { - "basename": "Блокирующие вызовы", - "path": "knowledge/dev/Блокирующие вызовы.md" } ], "omittedPaths": [], diff --git a/_inbox/Repeatable read.md b/_inbox/Repeatable read.md new file mode 100644 index 00000000..9313aae1 --- /dev/null +++ b/_inbox/Repeatable read.md @@ -0,0 +1,24 @@ +--- +aliases: + - повторяющееся чтение +tags: + - зрелость/🌱 +date: + - - 2024-06-19 +zero-link: + - "[[00 Базы Данных]]" +parents: + - "[[Уровни изоляций транзакций БД]]" +linked: +--- +**Repeatable read (повторяющееся чтение).** Уровень, при котором читающая транзакция «не видит» изменения данных, которые были ею ранее прочитаны. При этом никакая другая транзакция не может изменять данные, читаемые текущей транзакцией, пока та не окончена. ^38dd4b + +![](Pasted%20image%2020240619201149.png) + +Первая транзакция началась. Считала баланс первого пользователя. Обновила его, но не зафиксировала изменения. Началась вторая транзакция. Она также считала баланс первого пользователя, обновила его, но тоже не зафиксировала свои изменения. + +А теперь правильной окажется та транзакция, которая зафиксирует свои изменения первой. Первая транзакция выполнила коммит первой, поэтому коммит второй транзакции завершился ошибкой. + +Но если вторая транзакция не изменяла данные, а добавляла новые строчки, то исключения не было бы. Также проблем не будет, если мы обновим баланс второго пользователя. + +Но возникает закономерный вопрос: что делать с ошибкой, ведь мы хотели выполнить транзакцию, которая свалилась с исключением. Самое простое, что можно сделать — это повторить выполнение второй транзакции с новыми данными. Если исключение возникнет опять, то повторить снова. \ No newline at end of file diff --git a/_inbox/Serializable.md b/_inbox/Serializable.md new file mode 100644 index 00000000..9e16f77e --- /dev/null +++ b/_inbox/Serializable.md @@ -0,0 +1,13 @@ +--- +aliases: +tags: + - зрелость/🌱 +date: + - - 2024-06-19 +zero-link: + - "[[00 Базы Данных]]" +parents: + - "[[Уровни изоляций транзакций БД]]" +linked: +--- +**Serializable (упорядочиваемость).** Самый высокий уровень изолированности; транзакции полностью изолируются друг от друга, каждая выполняется так, как будто параллельных транзакций не существует. Только на этом уровне параллельные транзакции не подвержены эффекту «фантомного чтения». ^fdb385 \ No newline at end of file diff --git a/_inbox/Неповторяющееся чтение.md b/_inbox/Неповторяющееся чтение.md index f57952aa..4fa231b5 100644 --- a/_inbox/Неповторяющееся чтение.md +++ b/_inbox/Неповторяющееся чтение.md @@ -9,6 +9,15 @@ zero-link: - "[[00 Базы Данных]]" parents: - "[[Проблемы при параллельном выполнении нескольких транзакций]]" -linked: +linked: +link: https://struchkov.dev/blog/ru/transactional-isolation-levels/#%D0%BD%D0%B5%D0%BF%D0%BE%D0%B2%D1%82%D0%BE%D1%80%D1%8F%D1%8E%D1%89%D0%B5%D0%B5%D1%81%D1%8F-%D1%87%D1%82%D0%B5%D0%BD%D0%B8%D0%B5 --- -**Неповторяющееся чтение (non-repeatable reads).** Запрос с одними и теми же условиями даёт неодинаковые результаты в рамках транзакции. ^3e8781 \ No newline at end of file +**Неповторяющееся чтение (non-repeatable reads).** Запрос с одними и теми же условиями даёт неодинаковые результаты в рамках транзакции. ^3e8781 + +Эта проблема присутствует на уровне изоляции [Read committed](Read%20committed.md) и [Read uncommitted](Read%20uncommitted.md). + +Рассмотрим пример. Начинаем первую транзакцию. Считываем баланс пользователя, получаем значение 1000. Далее стартует вторая транзакция в отдельном потоке, а текущий поток засыпает. + +Во второй транзакции устанавливаем пользователю баланс равный 100_000. После чего закрываем вторую транзакцию. Баланс успешно обновился в БД. + +Первая транзакция продолжает выполнение. Снова запрашивает баланс пользователя из БД, на этот раз получает значение 100_000. Таким образом, вторая транзакция повлияла на выполнение первой. \ No newline at end of file diff --git a/_inbox/Потерянное обновление.md b/_inbox/Потерянное обновление.md index 99709ce6..697f7175 100644 --- a/_inbox/Потерянное обновление.md +++ b/_inbox/Потерянное обновление.md @@ -9,7 +9,8 @@ zero-link: - "[[00 Базы Данных]]" parents: - "[[Проблемы при параллельном выполнении нескольких транзакций]]" -linked: +linked: +link: https://struchkov.dev/blog/ru/transactional-isolation-levels/#%D0%BF%D0%BE%D1%82%D0%B5%D1%80%D1%8F%D0%BD%D0%BD%D0%BE%D0%B5-%D0%BE%D0%B1%D0%BD%D0%BE%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5 --- **Потерянное обновление (lost update).** Две параллельные транзакции меняют одни и те же данные, при этом итоговый результат обновления предсказать невозможно. ^23d01d @@ -86,6 +87,11 @@ public class LostUpdateExample { Вторая транзакция прибавляет к балансу пользователя 5 (31-34). После чего вторая транзакция также закрывается (38, 39). Баланс пользователя в БД равен 1005. Мы потеряли обновления, которые выполнила первая транзакция. Такое поведение называют [Race condition](Race%20condition.md). -Изменим уровень транзакций на более изолированный. В примере у нас используется `READ_COMMITTED`, установим  в строке 45. +Изменим уровень транзакций на более изолированный. В примере у нас используется `READ_COMMITTED`, установим [Repeatable read](Repeatable%20read.md) в строке 45. -В таком случае при выполнении нашего кода получаем исключение `PSQLException`. \ No newline at end of file +В таком случае при выполнении нашего кода получаем исключение `PSQLException`. + +![](Pasted%20image%2020240619201135.png) + +## Дополнительные материалы +- [Пример на Java](https://github.com/Example-uPagge/transactional/blob/master/jdbc-transaction/src/main/java/dev/struchkov/example/transaction/problems/LostUpdateExample.java) \ No newline at end of file diff --git a/knowledge/dev/database/Уровни изоляций транзакций БД.md b/knowledge/dev/database/Уровни изоляций транзакций БД.md index 0b65a411..9aad53f8 100644 --- a/knowledge/dev/database/Уровни изоляций транзакций БД.md +++ b/knowledge/dev/database/Уровни изоляций транзакций БД.md @@ -16,6 +16,6 @@ linked: ![](Read%20committed.md#^11df20) -**Repeatable read (повторяющееся чтение).** Уровень, при котором читающая транзакция «не видит» изменения данных, которые были ею ранее прочитаны. При этом никакая другая транзакция не может изменять данные, читаемые текущей транзакцией, пока та не окончена. +![](Repeatable%20read.md#^38dd4b) -**Serializable (упорядочиваемость).** Самый высокий уровень изолированности; транзакции полностью изолируются друг от друга, каждая выполняется так, как будто параллельных транзакций не существует. Только на этом уровне параллельные транзакции не подвержены эффекту «фантомного чтения». \ No newline at end of file +![](Serializable.md#^fdb385) diff --git a/meta/files/Pasted image 20240619201135.png b/meta/files/Pasted image 20240619201135.png new file mode 100644 index 00000000..4bfe4c9d Binary files /dev/null and b/meta/files/Pasted image 20240619201135.png differ diff --git a/meta/files/Pasted image 20240619201149.png b/meta/files/Pasted image 20240619201149.png new file mode 100644 index 00000000..57e503c8 Binary files /dev/null and b/meta/files/Pasted image 20240619201149.png differ