Last active
January 9, 2019 09:05
-
-
Save yv84/93035c8c2524fd7dc5cf5cab57935254 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Какие могут быть проблемы при параллельной работе транзакций: | |
| 1) Потерянное обновление - когда две транзакции читают и обновляют одну и ту же ячейку (поле в строке) параллельно. Например на счет начисляют проценты параллельно несколько транзакций. Одна пытается увеличить на 0,3%, вторая на 0,2%. Так как обе прочитали начальное значение одновременно, то в результате счет будет увеличен один раз. | |
| 2) Грязное чтение - когда одна транзакция меняет данные, а другая их читает, после чего первая откатывается. Например идут две транзакции, пытающиеся снять деньги со счета. На счету 100 рублей, первая пытается снять 30, но откатывается. Вторая пытается снять еще 50, но успевает прочитать значение счета после измененияи до коммита, то есть 70 рублей. В итоге на счету будет 20 рублей. | |
| 3) Неповторяемое чтение - когда одна транзакция читает данные несколько раз, а вторая успевает их обновить. | |
| Две транзакции работают параллельно, она начисляет процент, вторая снимает сумму со скидкой в зависимости от состояния счета. Начисление процента происходит по нетривиальной формуле. Первая транзакция читает счет и уходит на вычисления процента, вторая быстро успевает обновить счет, пока первая думает, первая транзакция начисляет процент по неактуальной сумме. | |
| 4) Фантомное чтение - когда одна транзакция читает строки по предикату, а вторая меняет их, так что повторное чтение в первой транзакции возвращает разный набор строк. Все предыдущие проблемы проявлялись на одной строке, фантомное чтение проявлятся когда строк более чем одна. Классический пример - баланс. Одна транзакция считает сумму средств на счетах, а вторая переводит с одного счета на другой (обновляет две записи по очереди). Первая транзакция может посчитать баланс между двумя обновлениями второй транзакции, получив неверный баланс. | |
| Вы запустили запрос в момент времен и Tl, а затем выполните его повторно в момент времени Т2, то в базе данных могут появиться дополнительные строки , что повлияет на полученные результаты. Отличие фантомного чтения от невоспроизводимого чтения состоит в том , что уже прочитанные данные не изменяются , но критерию запроса удовлетворяет больший объем данных, чем было до того. | |
| Эти 4 проблемы приводят к тому, что результат нескольких параллельных транзакций не соответствует какому-либо порядку их последовательного выполнения. | |
| Есть теорема о сериализуемости транзакций, которая говорит, что сериализуемость можно сделать используя двухфазный протокол блокировки. Когда в первой фазе навешиваются блокировки на строки, а во второй фазе снимаются. Причем для любого набора транзакций можно добиться их сериализумости если вторая фаза (снятие блокировок) происходит после коммита. | |
| Увы в реальности такая строгая сериализуемость убивает параллельность (и скорость работы) и повышает количество дедлоков, поэтому придумано два способа оптимизации: | |
| 1) Разные типы и гранулярности блокировок | |
| 2) Разные уровни изоляции (по сути разные правила навешивания блокировок) | |
| Само по себе название "уровень изоляции" плохо описывает происходящее. Ибо честная изоляция с точки зрения ACID, возможна только на уровне Serializable. Тогда сама база данных гарантирует, что любое количество транзакций, выполняющихся параллельно, имеют результат как при некотором последовательном выполнении. Все остальные уровни изоляции, кроме serializable, перекладывают на разработчика ответственность за сохранение изолированности транзакций. | |
| Сам уровни изоляции привязаны как раз к потенциальным проблемам, которые они допускают: | |
| 1) Serializable - обеспечивает честную изолированность транзакций. | |
| 2) Repeatable Read - допускает фантомные чтения, сам разработчик должен следить чтобы целостность данных не была нарушена из-за фантомных чтений. | |
| 3) Read Commited - допускает фантомные чтения и неповторяемые чтения. Соответственно сам разработчик должен следить за отсутствием проблем из-за неповторяемых чтений. | |
| 4) Read Uncommited - допускает фантомные чтения, неповторяемые чтения и даже грязные чтения. | |
| чтобы избежать Неповторяемое чтение нужно просто блочить те строки, с которыми работает транзакция, чтобы избежать Фантомное чтение нужно блочить все таблицы, с которыми работает транзакция. | |
| Propagation Behaviors Supported by Spring | |
| Propagation Description | |
| REQUIRED If there’s an existing transaction in progress, the current method should run within this | |
| transaction. Otherwise, it should start a new transaction and run within its own transaction. | |
| REQUIRES_NEW The current method must start a new transaction and run within its own transaction. | |
| If there’s an existing transaction in progress, it should be suspended. | |
| SUPPORTS If there’s an existing transaction in progress, the current method can run within this | |
| transaction. Otherwise, it is not necessary to run within a transaction. | |
| NOT_SUPPORTED The current method should not run within a transaction. If there’s an existing transaction in | |
| progress, it should be suspended. | |
| MANDATORY The current method must run within a transaction. If there’s no existing transaction in | |
| progress, an exception will be thrown. | |
| NEVER The current method should not run within a transaction. If there’s an existing transaction in | |
| progress, an exception will be thrown. | |
| NESTED If there’s an existing transaction in progress, the current method should run within the | |
| nested transaction (supported by the JDBC 3.0 save point feature) of this transaction. | |
| Otherwise, it should start a new transaction and run within its own transaction. This feature | |
| is unique to Spring (whereas the previous propagation behaviors have analogs in Java EE | |
| transaction propagation). The behavior is useful for situations such as batch processing, in | |
| which you’ve got a long running process (imagine processing 1 million records) and you | |
| want to chunk the commits on the batch. So you commit every 10,000 records. If something | |
| goes wrong, you roll back the nested transaction and you’ve lost only 10,000 records’ worth of | |
| work (as opposed to the entire 1 million). | |
| The problems caused by concurrent transactions can be categorized into four types: | |
| • Dirty read: For two transactions T1 and T2, T1 reads a field that has been updated by T2 but | |
| not yet committed. Later, if T2 rolls back, the field read by T1 will be temporary and invalid. | |
| • Nonrepeatable read: For two transactions T1 and T2, T1 reads a field and then T2 updates the | |
| field. Later, if T1 reads the same field again, the value will be different. | |
| • Phantom read: For two transactions T1 and T2, T1 reads some rows from a table and then | |
| T2 inserts new rows into the table. Later, if T1 reads the same table again, there will be | |
| additional rows. | |
| • Lost updates: For two transactions T1 and T2, they both select a row for update, and based on | |
| the state of that row, make an update to it. Thus, one overwrites the other when the second | |
| transaction to commit should have waited until the first one committed before performing its | |
| selection. | |
| Isolation Levels Supported by Spring | |
| Isolation Description | |
| DEFAULT Uses the default isolation level of the underlying database. For most databases, the default | |
| isolation level is READ_COMMITTED. | |
| READ_UNCOMMITTED Allows a transaction to read uncommitted changes by other transactions. The dirty read, | |
| nonrepeatable read, and phantom read problems may occur. | |
| READ_COMMITTED Allows a transaction to read only those changes that have been committed by other | |
| transactions. The dirty read problem can be avoided, but the nonrepeatable read and | |
| phantom read problems may still occur. | |
| REPEATABLE_READ Ensures that a transaction can read identical values from a field multiple times. For the | |
| duration of this transaction, updates made by other transactions to this field are prohibited. | |
| The dirty read and nonrepeatable read problems can be avoided, but the phantom read | |
| problem may still occur. | |
| SERIALIZABLE Ensures that a transaction can read identical rows from a table multiple times. For the | |
| duration of this transaction, inserts, updates, and deletes made by other transactions to this | |
| table are prohibited. All the concurrency problems can be avoided, but the performance | |
| will be low. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment