[Программирование, Java] Spring transaction management. Isolation and propagation

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
04-Авг-2020 12:30

Introduction
In my opinion transaction management is a really important topic for each backend developer. In general, people don’t pay attention to it while using Spring framework.
But I think, it is important to know how to use transactions properly. Because sometimes can happen that there was an exception thrown inside your method, but transaction was not rolled back and it is not clear why? Or some other “strange” cases.
@Transactional
In spring there is @Transactional annotation that can be used for wrapping a method in a transaction. We can use it with interfaces (lowest priority), classes or certain methods (highest priority).
@Transactional is applied only for public methods and method must be invoked from outside of the bean.
@Transactional annotation has multiple parameters. I would like to focus on two of them: Isolation and Propagation.
Isolation is one of the main properties of transactions (Atomicity, Consistency, Isolation, Durability). It describes visibility of changes applied by concurrent transactions to each other.
In Spring it is possible to set one of the 5 isolation level values: DEFAULT, READ_UNCOMMITTED, READ_COMMITED, REPETABLE_READ and SERIALIZABLE.
For example,
@Transactional (isolation=Isolation.READ_COMMITED)

Each of these isolation levels may have or haven’t different side effects: “dirty” read, non-repeatable read and phantom read. What each of them means?
“Dirty” read — one transaction can read changes of a concurrent transaction, that were not committed yet.
If you like more diagrams as I do:

Transaction T1 begins first, then we start transaction T2.
After that T1 changes row with id=10 in database and T2 reads it. Something wrong happens and T1 is rolled back. And recording in T2 is dirty now.
Non-repeatable read — one transaction reads the same row twice, but gets different values because between these reads the data was updated by the concurrent transaction.

Phantom read — one transaction runs the same query twice, but gets a different set of rows as result, because of the changes applied by another concurrent transaction.

Let’s go back to the isolation levels and check their possible side effects.
  • DEFAULT value is used when we want to use default isolation level of our RDBMS. Default value for PostgreSQL, Oracle and SQL server is READ_COMMITTED, for MySQL — REPEATABLE_READ.
  • with READ_UNCOMMITTED isolation level, we can have all three side effects
  • READ_COMMITTED isolation level has one change in comparison with READ_UNCOMMITTED — it prevents “dirty” reads.
  • REPEATABLE_READ prevents “dirty” and non-repeatable reads.
  • SERIALIZABLE isolation level prevents all mentioned above side effects. It performs all transactions in sequence.

Isolation level
Phantom read
Non-repeatable read
“Dirty” read
READ_UNCOMMITTED
possible
possible
possible
READ_COMMITTED
possible
possible
not possible
REPEATABLE_READ
possible
not possible
not possible
SERIALIZABLE
not possible
not possible
not possible
There is also another important parameter of @Transactional: propagation.
Propagation can be set to REQUIRED, REQUIRES_NEW, MANDATORY, SUPPORTS, NOT_SUPPORTED, NESTED or NEVER.
Example:
@Transactional (propagation=Propagation.REQUIRED)

  • REQUIRED propagation level uses an existing transaction if there is one. Otherwise creates a new transaction.
  • REQUIRES_NEW propagation level says to suspend outer transaction (if there is one) and create a new one.
  • MANDATORY propagation uses an existing transaction if there is one. Otherwise, an exception will be thrown.
  • SUPPORTS propagation level uses the current transaction if there is one. Otherwise, doesn’t create a new one.
  • NOT_SUPPORTED suspends current transaction if there is one.
  • NESTED creates nested transaction when there is an existing transaction already or works like REQUIRED if there is no transaction.
  • NEVER throws an exception if there is an active transaction.

Propagation
Calling method (outer)
Called method (inner)
REQUIRED
No
T2
REQUIRED
T1
T1
REQUIRES_NEW
No
T2
REQUIRES_NEW
T1
T2
MANDATORY
No
Exception
MANDATORY
T1
T1
NOT_SUPPORTED
No
No
NOT_SUPPORTED
T1
No
SUPPORTS
No
No
SUPPORTS
T1
T1
NEVER
No
No
NEVER
T1
Exception
NESTED
No
T2
NESTED
T1
T2
Also interesting is that Spring framework does automatic transaction rollback only for unchecked (Runtime) exceptions. To change it we can use rollbackFor parameter.
For example, we can put
@Transactional (rollbackFor=Exception.class)

Conclusion
In the article, I tried to describe how to use Isolation and Propagation parameters of @Transactional in Spring.
I remember how several years ago I had some problems with the chain of transactional method and I hope that my article can help other developers to avoid them and have more clear understanding of the topic.
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_programmirovanie (Программирование), #_java, #_java, #_spring, #_transactions, #_programmirovanie (
Программирование
)
, #_java
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 10-Май 03:01
Часовой пояс: UTC + 5