vault backup: 2024-06-19 19:58:52
This commit is contained in:
parent
55c84d1313
commit
2f3c178ed0
22
.obsidian/plugins/home-tab/data.json
vendored
22
.obsidian/plugins/home-tab/data.json
vendored
@ -24,24 +24,24 @@
|
||||
"unresolvedLinks": false,
|
||||
"recentFilesStore": [
|
||||
{
|
||||
"filepath": "_inbox/Грязное чтение.md",
|
||||
"timestamp": 1718816024825
|
||||
},
|
||||
{
|
||||
"filepath": "_inbox/Read uncommitted.md",
|
||||
"timestamp": 1718816022761
|
||||
"filepath": "knowledge/dev/database/Проблемы при параллельном выполнении нескольких транзакций.md",
|
||||
"timestamp": 1718816327221
|
||||
},
|
||||
{
|
||||
"filepath": "knowledge/dev/database/Уровни изоляций транзакций БД.md",
|
||||
"timestamp": 1718816010418
|
||||
"timestamp": 1718816268102
|
||||
},
|
||||
{
|
||||
"filepath": "knowledge/dev/database/Проблемы при параллельном выполнении нескольких транзакций.md",
|
||||
"timestamp": 1718815991051
|
||||
"filepath": "_inbox/Грязное чтение.md",
|
||||
"timestamp": 1718816237993
|
||||
},
|
||||
{
|
||||
"filepath": "_inbox/Транзакция БД.md",
|
||||
"timestamp": 1718815984227
|
||||
"filepath": "_inbox/Read committed.md",
|
||||
"timestamp": 1718816202958
|
||||
},
|
||||
{
|
||||
"filepath": "_inbox/Read uncommitted.md",
|
||||
"timestamp": 1718816179266
|
||||
}
|
||||
],
|
||||
"bookmarkedFileStore": [],
|
||||
|
@ -1,20 +1,24 @@
|
||||
{
|
||||
"recentFiles": [
|
||||
{
|
||||
"basename": "Грязное чтение",
|
||||
"path": "_inbox/Грязное чтение.md"
|
||||
},
|
||||
{
|
||||
"basename": "Read uncommitted",
|
||||
"path": "_inbox/Read uncommitted.md"
|
||||
"basename": "Проблемы при параллельном выполнении нескольких транзакций",
|
||||
"path": "knowledge/dev/database/Проблемы при параллельном выполнении нескольких транзакций.md"
|
||||
},
|
||||
{
|
||||
"basename": "Уровни изоляций транзакций БД",
|
||||
"path": "knowledge/dev/database/Уровни изоляций транзакций БД.md"
|
||||
},
|
||||
{
|
||||
"basename": "Проблемы при параллельном выполнении нескольких транзакций",
|
||||
"path": "knowledge/dev/database/Проблемы при параллельном выполнении нескольких транзакций.md"
|
||||
"basename": "Грязное чтение",
|
||||
"path": "_inbox/Грязное чтение.md"
|
||||
},
|
||||
{
|
||||
"basename": "Read committed",
|
||||
"path": "_inbox/Read committed.md"
|
||||
},
|
||||
{
|
||||
"basename": "Read uncommitted",
|
||||
"path": "_inbox/Read uncommitted.md"
|
||||
},
|
||||
{
|
||||
"basename": "Транзакция БД",
|
||||
@ -195,10 +199,6 @@
|
||||
{
|
||||
"basename": "Redis",
|
||||
"path": "_inbox/Redis.md"
|
||||
},
|
||||
{
|
||||
"basename": "Fingerprint файлов",
|
||||
"path": "_inbox/Fingerprint файлов.md"
|
||||
}
|
||||
],
|
||||
"omittedPaths": [],
|
||||
|
14
_inbox/Read committed.md
Normal file
14
_inbox/Read committed.md
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
aliases:
|
||||
tags:
|
||||
- зрелость/🌱
|
||||
date:
|
||||
- - 2024-06-19
|
||||
zero-link:
|
||||
- "[[00 Базы Данных]]"
|
||||
parents:
|
||||
- "[[Уровни изоляций транзакций БД]]"
|
||||
linked:
|
||||
---
|
||||
**Read committed (чтение фиксированных данных).** Большинство промышленных СУБД по умолчанию используют именно этот уровень. На этом уровне обеспечивается защита от «грязного» чтения, тем не менее, в процессе работы одной транзакции другая может быть успешно завершена и сделанные ею изменения зафиксированы. В итоге первая транзакция будет работать с другим набором данных. ^11df20
|
||||
|
@ -2,9 +2,12 @@
|
||||
aliases:
|
||||
tags:
|
||||
- зрелость/🌱
|
||||
date: [[2024-06-19]]
|
||||
zero-link:
|
||||
parents:
|
||||
date:
|
||||
- - 2024-06-19
|
||||
zero-link:
|
||||
- "[[00 Базы Данных]]"
|
||||
parents:
|
||||
- "[[Уровни изоляций транзакций БД]]"
|
||||
linked:
|
||||
---
|
||||
**Read uncommitted (чтение незафиксированных данных).** Если несколько параллельных транзакций пытаются изменять одну и ту же строку таблицы, то в окончательном варианте строка будет иметь значение, определенное всем набором успешно выполненных транзакций. ^52421e
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
aliases:
|
||||
aliases:
|
||||
- dirty reads
|
||||
tags:
|
||||
- зрелость/🌱
|
||||
date:
|
||||
@ -8,8 +9,76 @@ zero-link:
|
||||
- "[[00 Базы Данных]]"
|
||||
parents:
|
||||
- "[[Проблемы при параллельном выполнении нескольких транзакций]]"
|
||||
linked:
|
||||
linked:
|
||||
link: https://struchkov.dev/blog/ru/transactional-isolation-levels/#%D0%B3%D1%80%D1%8F%D0%B7%D0%BD%D0%BE%D0%B5-%D1%87%D1%82%D0%B5%D0%BD%D0%B8%D0%B5
|
||||
---
|
||||
**«Грязное» чтение** (dirty reads) — в результатах запроса появляются промежуточные результаты параллельной транзакции, которая ещё не завершилась.
|
||||
|
||||
Эта проблема наблюдается при уровне изоляции `READ_UNCOMMITTED`.
|
||||
Эта проблема наблюдается при уровне изоляции [Read uncommitted](Read%20uncommitted.md).
|
||||
|
||||
Рассмотрим на примере. У нас будет два параллельных потока. В первом мы открываем транзакцию и устанавливаем новый баланс первому пользователю равным 100_000. Но транзакцию не коммитим. Вместо этого, запускаем вторую параллельную транзакцию в отдельном потоке, а текущий поток засыпает на 2 секунды.
|
||||
|
||||
Во второй транзакции считывается баланс пользователя из БД и выводится в консоль. Значение баланса будет 100_000, несмотря на то, что первая транзакция ещё не закоммитила свои изменения.
|
||||
|
||||
Но дальше самое интересное, мы выполняем rollback первой транзакции, и баланс пользователя снова становится 1000. То есть вторая транзакция работала с не валидными данными.
|
||||
|
||||
```java
|
||||
public class DirtyReadExample {
|
||||
|
||||
private static final int ISOLATION_LEVEL = Connection.TRANSACTION_READ_UNCOMMITTED;
|
||||
|
||||
public static void main(String[] args) throws SQLException, InterruptedException {
|
||||
try (
|
||||
final Connection connection = Repository.getConnectionH2();
|
||||
final Statement statement = connection.createStatement()
|
||||
) {
|
||||
connection.setAutoCommit(false);
|
||||
connection.setTransactionIsolation(ISOLATION_LEVEL);
|
||||
|
||||
statement.executeUpdate("UPDATE person SET balance = 100000 WHERE id = 1");
|
||||
|
||||
new OtherTransaction().start();
|
||||
Thread.sleep(2000);
|
||||
connection.rollback();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class OtherTransaction extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
try (
|
||||
final Connection connection = Repository.getConnectionH2();
|
||||
final Statement statement = connection.createStatement()
|
||||
) {
|
||||
connection.setAutoCommit(false);
|
||||
connection.setTransactionIsolation(ISOLATION_LEVEL);
|
||||
|
||||
final ResultSet resultSet = statement.executeQuery("SELECT * FROM person WHERE id = 1");
|
||||
while (resultSet.next()) {
|
||||
System.out.println("Balance: " + resultSet.getString("balance"));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
System.out.println(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Результат работы примера:
|
||||
|
||||
```log
|
||||
Balance: 100000
|
||||
```
|
||||
|
||||
Для устранения этого эффекта устанавливаем уровень изоляции в [Read committed](Read%20committed.md). Теперь при выполнении второй транзакции получаем баланс 1000, вместо 100_000.
|
||||
|
||||
Результат работы примера с `READ_COMMITTED`:
|
||||
|
||||
```log
|
||||
Balance: 1000
|
||||
```
|
||||
## Дополнительные материалы
|
||||
- [Пример реализации на Java](https://github.com/Example-uPagge/transactional/blob/master/jdbc-transaction/src/main/java/dev/struchkov/example/transaction/problems/DirtyReadExample.java)
|
@ -2,8 +2,6 @@
|
||||
aliases:
|
||||
- phantom reads
|
||||
- фантомное чтение
|
||||
- dirty reads
|
||||
- грязное чтение
|
||||
- неповторяющееся чтение
|
||||
- non-repeatable reads
|
||||
- потерянное обновление
|
||||
|
@ -10,9 +10,11 @@ parents:
|
||||
- "[[Транзакция БД]]"
|
||||
linked:
|
||||
---
|
||||
У большинства СУБД по умолчанию установлен уровень изоляции [Read committed](Read%20committed.md), а [Read uncommitted](Read%20uncommitted.md) может вовсе не поддерживаться. Более того, некоторые уровни изоляции могут и не иметь описанных далее проблем. Здесь всё индивидуально, изучайте документацию СУБД.
|
||||
|
||||
![](Read%20uncommitted.md#^52421e)
|
||||
|
||||
**Read committed (чтение фиксированных данных).** Большинство промышленных СУБД по умолчанию используют именно этот уровень. На этом уровне обеспечивается защита от «грязного» чтения, тем не менее, в процессе работы одной транзакции другая может быть успешно завершена и сделанные ею изменения зафиксированы. В итоге первая транзакция будет работать с другим набором данных.
|
||||
![](Read%20committed.md#^11df20)
|
||||
|
||||
**Repeatable read (повторяющееся чтение).** Уровень, при котором читающая транзакция «не видит» изменения данных, которые были ею ранее прочитаны. При этом никакая другая транзакция не может изменять данные, читаемые текущей транзакцией, пока та не окончена.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user