{"id":84,"date":"2023-01-31T12:25:33","date_gmt":"2023-01-31T05:25:33","guid":{"rendered":"https:\/\/thoaicoder.com\/?p=84"},"modified":"2024-02-03T23:21:05","modified_gmt":"2024-02-03T16:21:05","slug":"manage-transaction-with-spring-transactional","status":"publish","type":"post","link":"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/","title":{"rendered":"Manage transactions with Spring @Transactional"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><strong>1. Why do we need transactions?<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When working on an enterprise system that persists data in a database, we mainly deal with transactions. For example, in a bank transfer transaction, if an amount of money is to be transferred from an A account to a B account, these operations must be processed: <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Check your Account A balance <\/li>\n\n\n\n<li>Debit the amount of Account A<\/li>\n\n\n\n<li>Credit the amount to Account B<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">You can easily understand that the below criteria must be satisfied regardless this transaction is executed successfully or not, otherwise it will be a disaster:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The whole transaction is only successful if all operations are successful<\/li>\n\n\n\n<li>If an error happens when checking the balance, withdrawing the amount from the account, or credit in the other account<strong>, the whole process should not be performed<\/strong>. Otherwise, inconsistencies could occur, such as leaving Account A negative or withdrawing money from A but not crediting B. <\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"703\" height=\"379\" src=\"https:\/\/thoaicoder.com\/wp-content\/uploads\/2023\/02\/image-1.png\" alt=\"\" class=\"wp-image-159\" srcset=\"https:\/\/thoaicoder.com\/wp-content\/uploads\/2023\/02\/image-1.png 703w, https:\/\/thoaicoder.com\/wp-content\/uploads\/2023\/02\/image-1-300x162.png 300w\" sizes=\"auto, (max-width: 703px) 100vw, 703px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">In order to deal with transactions, we have to comply with their properties &#8211;  <a href=\"https:\/\/en.wikipedia.org\/wiki\/ACID\">ACID<\/a>, so it is critical to understand transaction mechanisms and config transactions in the right way.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>2. What is @Transactional in Spring?<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In the Spring framework, <strong>@Transactional<\/strong> was introduced in version 1.2, it is an annotation that provides an easy way to manage application transactions. It enables developers to use a consistent programming model in any environment and easily control a transaction&#8217;s scope and comply with ACID properties.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>3. Configure transactions<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Spring 3.1 introduces the <strong>@EnableTransactionManagement<\/strong> annotation but with Spring Boot projects that have a <strong>spring-data-*<\/strong> or <strong>spring-tx dependencies<\/strong> on the classpath, then transaction management will be enabled by default.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There are a few ways to enable transactions for our business using Spring, but the most popular way is about using <strong>@Transactional<\/strong> on top of a class or a method.<\/p>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Service\n@Transactional\npublic class BankTransferService {\n   ...\n}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Service\npublic class BankTransferService {\n\n  @Transactional\n  public void transfer(...) {\n    ...\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">There are a few parameters in this annotation but the most important parameters are isolation &amp; propagation, it is not easy to understand these configurations without experimental so I will try to demonstrate each configuration using coding examples.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>4. Propagation<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Propagation provides settings for how the transaction should behave if it i<strong>s called by another method or another class (parent transaction).<\/strong> Propagation value can be:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>REQUIRED (default)<\/strong>: joins the parent transaction. If one does not exist, create it<\/li>\n\n\n\n<li><strong>MANDATORY<\/strong>: uses the parent transaction and <strong>throws an exception<\/strong> if one does not exist<\/li>\n\n\n\n<li><strong>NESTED<\/strong>: creates a transaction parallel to the parent transaction. If one does not exist, create it<\/li>\n\n\n\n<li><strong>NEVER<\/strong>: does not allow transaction execution. If a transaction exists, <strong>an exception will be thrown<\/strong><\/li>\n\n\n\n<li><strong>NOT_SUPPORTED<\/strong>: does not allow transaction execution. Suspends the parent transaction, if one exists<\/li>\n\n\n\n<li><strong>REQUIRES_NEW<\/strong>: creates a new transaction and suspends the parent transaction<\/li>\n\n\n\n<li><strong>SUPPORTS<\/strong>: joins the parent transaction. If one does not exist, it does not create it<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>4.1. Propagation.REQUIRES<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I will use a scenario of creating a <strong>Contact <\/strong>with a <strong>Note <\/strong>in a CRM system which is stored in the contact and note table in MySQL to demonstrate all examples in this article. <strong>ContactService <\/strong>is the parent class, it will use <strong>NoteService <\/strong>to add a note for a newly created contact in the<strong> save(RequestCreateContactDTO contactDTO) <\/strong>method.<\/p>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Service\n@Transactional\npublic class NoteService{\n   @Autowire\n   private NoteDao noteDao;\n\n   public void save(NoteDto noteDto, Long contactId) {\n      (4) throw new RuntimeException(\"Error\");\n   }\n}\n\n@Service\n@Transactional\npublic class ContactService{\n   @Autowire\n   private NoteService noteService;\n   @Autowire\n   private ContactDao contactDao;\n\n   public void save(RequestCreateContactDTO contactDTO) {\n      Contact contact = new Contact;\n      \/\/init contact by contactDTO\n      ...\n      (2) contact = contactDao.save(contact);\n      (3) noteService.save(contactDTO.getNoteDto(), contact.getId());\n   }\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Spring will create a transaction which default values for propagation and isolation, REQUIRED and DEFAULT. This transaction will be used in ContactService.save and NoteService.save<\/li>\n\n\n\n<li>Save contact to MySQL<\/li>\n\n\n\n<li>Add a note for newly created contact using NoteService<\/li>\n\n\n\n<li>However, NoteService.save throws an exception<\/li>\n\n\n\n<li><strong>Then, neither the contact nor the note is saved, because a rollback for both was done.<\/strong><\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>4.2. Propagation.MANDATORY<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, we configure <strong>propagation = Propagation.MANDATORY in NoteService<\/strong> and <strong>remove @Transactional in ContactService<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Service\n@Transactional(propagation = Propagation.MANDATORY)\npublic class NoteService{\n   @Autowire\n   private NoteDao noteDao;\n\n   public void save(NoteDto noteDto, Long contactId) {\n      Note note= new Note();\n      \/\/init note by noteDto\n      ...\n      note.setContactId(contactId);\n      noteDao.save(note);\n   }\n}\n\n@Service\npublic class ContactService{\n   @Autowire\n   private NoteService noteService;\n   @Autowire\n   private ContactDao contactDao;\n\n   public void save(RequestCreateContactDTO contactDTO) {\n      Contact contact = new Contact();\n      \/\/init contact by contactDTO\n      ...\n      (2) contact = contactDao.save(contact);\n      (3) noteService.save(contactDTO.getNoteDto(), contact.getId());\n   }\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Spring will not create a transaction in ContactService.save<\/li>\n\n\n\n<li>Save contact to MySQL<\/li>\n\n\n\n<li>Add a note for newly created contact using NoteService<\/li>\n\n\n\n<li><strong>An exception is thrown: <em>org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation &#8216;mandatory&#8217;<\/em><\/strong><\/li>\n\n\n\n<li>The contact created at (2) was still saved successfully because there is no transaction in ContactService.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>4.3. Propagation.<strong>NESTED<\/strong><\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, we configure <strong>propagation = Propagation.<strong><strong>NESTED<\/strong><\/strong> in NoteService<\/strong>. Please note that Hibernate does not support this type of transaction. Since we use SpringData and Hibernate, so it&#8217;s impossible to present a real code about this propagation. It would be necessary to show codes with JDBCTemplate, which is not the focus of this article. So I will just use a fake example to explain it.<\/p>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Service\n@Transactional(propagation = Propagation.NESTED)\npublic class NoteService{\n   @Autowire\n   private NoteDao noteDao;\n\n   public void save(NoteDto noteDto, Long contactId) {\n      Note note= new Note();\n      \/\/init note by noteDto\n      ...\n      note.setContactId(contactId);\n      (4) noteDao.save(note);\n      (6) throw new RuntimeException(\"Error\");\n   }\n}\n\n@Service\n@Transactional\npublic class ContactService{\n   @Autowire\n   private NoteService noteService;\n   @Autowire\n   private ContactDao contactDao;\n\n   public void save(RequestCreateContactDTO contactDTO) {\n      Contact contact = new Contact();\n      \/\/init contact by contactDTO\n      ...\n      (2) contact = contactDao.save(contact);\n      (3) noteService.save(contactDTO.getNoteDto(), contact.getId());\n   }\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Spring will create a transaction in ContactService.save<\/li>\n\n\n\n<li>Save contact to MySQL<\/li>\n\n\n\n<li>Add a note for newly created contact using NoteService<\/li>\n\n\n\n<li>Save note to MySQL<\/li>\n\n\n\n<li><strong>Spring started a subordinate transaction (NESTED)<\/strong><\/li>\n\n\n\n<li>NoteService.save throws an exception<\/li>\n\n\n\n<li><strong>The contact will be still saved<\/strong> <strong>but the note because they are in different transactions<\/strong><\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>4.4. Propagation.<strong><strong>NEVER<\/strong><\/strong><\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Service\n@Transactional(propagation = Propagation.NEVER)\npublic class NoteService{\n   @Autowire\n   private NoteDao noteDao;\n\n   public void save(NoteDto noteDto, Long contactId) {\n       ....\n   }\n}\n\n@Service\n@Transactional\npublic class ContactService{\n   @Autowire\n   private NoteService noteService;\n   @Autowire\n   private ContactDao contactDao;\n\n   public void save(RequestCreateContactDTO contactDTO) {\n      Contact contact = new Contact();\n      \/\/init contact by contactDTO\n      ...\n      (2) contact = contactDao.save(contact);\n      (3) noteService.save(contactDTO.getNoteDto(), contact.getId());\n   }\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Spring will create a transaction in ContactService.save<\/li>\n\n\n\n<li>Save contact to MySQL<\/li>\n\n\n\n<li>Add a note for newly created contact using NoteService<\/li>\n\n\n\n<li><strong>An exception is thrown: org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation &#8216;never&#8217;<\/strong><\/li>\n\n\n\n<li>The contact created at (2) will be rollbacked<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>4.5. Propagation.<strong><strong>NOT_SUPPORTED<\/strong><\/strong><\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Service\n@Transactional(propagation = Propagation.NOT_SUPPORTED)\npublic class NoteService{\n   @Autowire\n   private NoteDao noteDao;\n\n   public void save(NoteDto noteDto, Long contactId) {\n       Note note= new Note();\n      \/\/init note by noteDto\n      ...\n      note.setContactId(contactId);\n      (5) noteDao.save(note);\n   }\n}\n\n@Service\n@Transactional\npublic class ContactService{\n   @Autowire\n   private NoteService noteService;\n   @Autowire\n   private ContactDao contactDao;\n\n   public void save(RequestCreateContactDTO contactDTO) {\n      Contact contact = new Contact();\n      \/\/init contact by contactDTO\n      ...\n      (2) contact = contactDao.save(contact);\n      (3) noteService.save(contactDTO.getNoteDto(), contact.getId());\n   }\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Spring will create a transaction in ContactService.save<\/li>\n\n\n\n<li>Save contact to MySQL<\/li>\n\n\n\n<li>Add a note for newly created contact using NoteService<\/li>\n\n\n\n<li>Spring stops the transaction in ContactService.save<\/li>\n\n\n\n<li>Save note to MySQL<\/li>\n\n\n\n<li><strong>A weird behavior happens:  Spring pauses the executions for a period of time and then throws an exception: org.springframework.dao.PessimisticLockingFailureException: could not execute statement; SQL [n\/a]; nested exception is org.hibernate.PessimisticLockException: could not execute statement<\/strong><\/li>\n\n\n\n<li><strong>Neither the contact nor the note is saved because a rollback for both was done.<\/strong><\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">This behavior is because at (4) Spring stops the transaction in ContactService.save so the contact created at (2) is locked and still has not been saved to the database. So at (5) we try to access the locked contact to save the note which is not possible.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>4.6. Propagation.REQUIRES_NEW<\/strong><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In order to explain this propagation, I will use a different example saving two entities into the database without any relationship to avoid the same exception with 4.5. Propagation.NOT_SUPPORTED. In this example, we have an AccountContactService to create an account using AccountService and then create a Contact using ContactService.<\/p>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Service\n@Transactional\npublic class AccountService{\n   @Autowire\n   private AccountDao accountDao;\n\n   public void save(AccountDto accountDto) {\n      Account account = new Account ();\n      \/\/init account by accountDto\n      ...\n      (2)accountDao.save(account);\n   }\n}\n\n@Service\n@Transactional(propagation = Propagation.REQUIRES_NEW)\npublic class ContactService{\n   @Autowire\n   private ContactDao contactDao;\n\n   public void save(RequestCreateContactDTO contactDTO) {\n      Contact contact = new Contact();\n      \/\/init contact by contactDTO\n      ...\n      (6) contact = contactDao.save(contact);\n      (7) throw new FakeException(\"Error\");\n   }\n}\n\n@Service\n@Transactional\npublic class AccountContactService{\n   @Autowire\n   private AccountService accountService;\n   @Autowire\n   private ContactService contactService;\n\n   public void save(RequestCreateAccountDTO requestCreateAccountDto ) { \n      try {\n          (2) accountService.save(requestCreateAccountDto.getAccountDto());\n          (3) contactService.save(requestCreateAccountDto.getContactDto());\n      } catch (FakeException e) {\n         (8) throw e;\n      }\n   }\n}<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Spring will create a transaction in AccountContactService.save and AccountService.save<\/li>\n\n\n\n<li>Save account to MySQL using AccountContactService.save<\/li>\n\n\n\n<li>Save contact to MySQL using ContactService.save<\/li>\n\n\n\n<li>Spring pauses the above transaction<\/li>\n\n\n\n<li><strong>Spring started a new transaction for ContactService.save<\/strong><\/li>\n\n\n\n<li>Save contact to MySQL<\/li>\n\n\n\n<li>Throw a FakeException, then rollback to contact<\/li>\n\n\n\n<li>Stop ContactService.save transaction and resume AccountContactService transaction then goes to catch block<\/li>\n\n\n\n<li><strong>The account will be still saved<\/strong> <strong>but the contact because they are in different transactions<\/strong><\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>4.7. Propagation.SUPPORT<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Service\n@Transactional(propagation = Propagation.SUPPORT)\npublic class ContactService{\n   @Autowire\n   private ContactDao contactDao;\n\n   public void save(RequestCreateContactDTO contactDTO) {\n      Contact contact = new Contact();\n      \/\/init contact by contactDTO\n      ...\n      contact = contactDao.save(contact);\n   }\n}\n\n@Service\npublic class AccountContactService{\n   @Autowire\n   private AccountService accountService;\n   @Autowire\n   private ContactService contactService;\n\n   @Transactional\n   public void saveWithTransaction(RequestCreateAccountDTO requestCreateAccountDto ) { \n      accountService.save(requestCreateAccountDto.getAccountDto());\n      ...\n   }\n\n   public void saveWithoutTransaction(RequestCreateAccountDTO requestCreateAccountDto ) { \n      accountService.save(requestCreateAccountDto.getAccountDto());\n      ...\n   }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, ContactService is configured with SUPPORT propagation, it is used by two methods in AccountContactService, <strong>saveWithTransaction <\/strong>with @Transactional and <strong>saveWithoutTransaction <\/strong>without @Transactional.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The result is that all contacts are saved without any problems.&nbsp;The <strong>saveWithoutTransaction <\/strong>method does not start a transaction, so&nbsp;the&nbsp;ContactService.save<em> <\/em>method is executed non-transactionally. The&nbsp;<strong>saveWithTransaction <\/strong>method creates a transaction, so now&nbsp;ContactService.save executes transactionally way.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>5. Isolation<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Isolation provides configurations of how the transactions see each other. Isolation value can be:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>DEFAULT<\/strong>: uses the isolation defined directly in the database<\/li>\n\n\n\n<li><strong>READ_COMMITED<\/strong>: cannot read data that has not yet been committed<\/li>\n\n\n\n<li><strong>READ_UNCOMMITED<\/strong>: can read data that has not yet been committed<\/li>\n\n\n\n<li><strong>REPEATABLE_READ<\/strong>: indicates that if a transaction initially reads a set of rows from the database, the next several readings must have the same result. If rows were updated, deleted, or inserted and are expected to appear in this reading, an exception is thrown<\/li>\n\n\n\n<li><strong>SERIALIZABLE<\/strong>: indicates that the transaction sees only the data that belongs to it. That is, even if other data has been committed in other transactions, they will not be visible. It happens because they were not manipulated in the current transaction. It is the most restrictive isolation<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>5.1. Isolation.READ_COMMITED<\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Transactional(isolation = Isolation.READ_COMMITTED)\npublic Contact saveAndReturn(RequestCreateContactDTO contactDTO) {\n Contact contact = new Contact();\r\n \/\/init contact by contactDTO\r\n ...\r\n this.contactService.save(contact);\n return this.searchService.findContactByUuid(contact.getUuid());\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this example, the contact was saved in&nbsp;<strong>save<\/strong>. However, the&nbsp;<strong>saveAndReturn <\/strong>method has not finished yet and this transaction has not yet been committed. So, due to the READ_COMMITTED isolation, the&nbsp;<strong>findContactByUuid <\/strong>method cannot get the contact. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>5.2. Isolation.<strong>READ_UNCOMMITED<\/strong><\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Transactional(isolation = Isolation.READ_UNCOMMITTED)\npublic Contact saveAndReturn(RequestCreateContactDTO contactDTO) {\n Contact contact = new Contact();\n \/\/init contact by contactDTO\n ...\n this.contactService.save(contact);\n return this.searchService.findContactByUuid(contact.getUuid());\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This example is the same as the 5.1 example but we change isolation to READ_UNCOMMITTED, the result is that the findContactByUuid method can get the newly created contact due to READ_UNCOMMITTED allowing to do that.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>5.3. Isolation.<strong><strong>REPEATABLE_READ<\/strong><\/strong><\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Transactional(isolation = Isolation.REPEATABLE_READ)\npublic List&lt;Contact&gt;updateThenReturn() {\n try {\n  List&lt;Contact&gt; contacts = contactService.getAllContacts();\n  Contact contact = contacts.get(0);\n  student.setFirstName(\"Thoai\");\n  contactService.save(contact );\n  return contactService.getAllContacts();\n } catch (CannotAcquireLockException e) {\n  throw e;\n }\n\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this code, the first reading of all contacts is done using the&nbsp;<strong>getAllContacts <\/strong>method. After that, an update is made on the first. However, when trying to read all contacts again, an error occurs. This is because the REPEATABLE_READ isolation identified that the reading would no longer be the same, as an updated row was returned, which was modified by a concurrent transaction (<strong>contactService.save<\/strong>).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>5.4. Isolation.<strong><strong>SERIALIZABLE<\/strong><\/strong><\/strong><\/h3>\n\n\n\n<pre class=\"wp-block-code has-white-color has-black-background-color has-text-color has-background\" style=\"padding-top:var(--wp--preset--spacing--40);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--40);padding-left:var(--wp--preset--spacing--40)\"><code>@Transactional(isolation = Isolation.SERIALIZABLE)\npublic void updateThenReturn() {\n contactService.getAllContacts();\n Contact contact = contacts.get(0);\n student.setFirstName(\"Thoai\");\n contactService.save(contact );\n return contactService.getAllContacts();\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this code, contacts that were shown the first time will be returned exactly the same the second time. Even with the updated contact in&nbsp;<strong>contactService.save<\/strong>, it will not appear in the second query. This is because this new contact was created by a new transaction and not by the one that is being executed (execute&nbsp;method), with SERIALIZABLE isolation. This isolation is the most restrictive isolation and limits its scope only to the current transaction.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>6. Conclusion<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Transactions are really important in most IT systems nowadays, we usually deal with transactions in our daily work so it is really important to use them in the right way, especially in the high volume of transactions systems such as e-commerce that may execute a thousand transactions per second and perform critical data as money, stock.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In distributed systems such as micro-services, we may need to deal with distributed transactions which are transactions executed by multiple services, so we need another technique as Two-Phases Commit or SAGA. You can research more on this topic: <a href=\"https:\/\/microservices.io\/patterns\/data\/saga.html\">https:\/\/microservices.io\/patterns\/data\/saga.html<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>1. Why do we need transactions? When working on an enterprise system that persists data [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":139,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[28,23,49],"class_list":["post-84","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","tag-java","tag-spring","tag-transactional"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v19.14 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Manage transactions with Spring @Transactional - I \u2764 Code<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Manage transactions with Spring @Transactional - I \u2764 Code\" \/>\n<meta property=\"og:description\" content=\"1. Why do we need transactions? When working on an enterprise system that persists data [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/\" \/>\n<meta property=\"og:site_name\" content=\"I \u2764 Code\" \/>\n<meta property=\"article:published_time\" content=\"2023-01-31T05:25:33+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-02-03T16:21:05+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/thoaicoder.com\/wp-content\/uploads\/2023\/01\/1520154762008.jpeg\" \/>\n\t<meta property=\"og:image:width\" content=\"471\" \/>\n\t<meta property=\"og:image:height\" content=\"270\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Thoai\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Thoai\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/\"},\"author\":{\"name\":\"Thoai\",\"@id\":\"https:\/\/thoaicoder.com\/#\/schema\/person\/a3304c209434f63c501b05622d7d2720\"},\"headline\":\"Manage transactions with Spring @Transactional\",\"datePublished\":\"2023-01-31T05:25:33+00:00\",\"dateModified\":\"2024-02-03T16:21:05+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/\"},\"wordCount\":1626,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/thoaicoder.com\/#\/schema\/person\/a3304c209434f63c501b05622d7d2720\"},\"keywords\":[\"Java\",\"Spring\",\"Transactional\"],\"articleSection\":[\"Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/\",\"url\":\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/\",\"name\":\"Manage transactions with Spring @Transactional - I \u2764 Code\",\"isPartOf\":{\"@id\":\"https:\/\/thoaicoder.com\/#website\"},\"datePublished\":\"2023-01-31T05:25:33+00:00\",\"dateModified\":\"2024-02-03T16:21:05+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/thoaicoder.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Manage transactions with Spring @Transactional\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/thoaicoder.com\/#website\",\"url\":\"https:\/\/thoaicoder.com\/\",\"name\":\"I \u2764 Code\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/thoaicoder.com\/#\/schema\/person\/a3304c209434f63c501b05622d7d2720\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/thoaicoder.com\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/thoaicoder.com\/#\/schema\/person\/a3304c209434f63c501b05622d7d2720\",\"name\":\"Thoai\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/thoaicoder.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/thoaicoder.com\/wp-content\/uploads\/2023\/03\/photo_2023-01-05_22-53-32.jpg\",\"contentUrl\":\"https:\/\/thoaicoder.com\/wp-content\/uploads\/2023\/03\/photo_2023-01-05_22-53-32.jpg\",\"width\":640,\"height\":640,\"caption\":\"Thoai\"},\"logo\":{\"@id\":\"https:\/\/thoaicoder.com\/#\/schema\/person\/image\/\"},\"sameAs\":[\"https:\/\/thoaicoder.com\",\"https:\/\/www.linkedin.com\/in\/huu-thoai-nguyen\/\"],\"url\":\"https:\/\/thoaicoder.com\/index.php\/author\/admin_cvyxq4b8\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Manage transactions with Spring @Transactional - I \u2764 Code","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/","og_locale":"en_US","og_type":"article","og_title":"Manage transactions with Spring @Transactional - I \u2764 Code","og_description":"1. Why do we need transactions? When working on an enterprise system that persists data [&hellip;]","og_url":"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/","og_site_name":"I \u2764 Code","article_published_time":"2023-01-31T05:25:33+00:00","article_modified_time":"2024-02-03T16:21:05+00:00","og_image":[{"width":471,"height":270,"url":"https:\/\/thoaicoder.com\/wp-content\/uploads\/2023\/01\/1520154762008.jpeg","type":"image\/jpeg"}],"author":"Thoai","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Thoai","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/#article","isPartOf":{"@id":"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/"},"author":{"name":"Thoai","@id":"https:\/\/thoaicoder.com\/#\/schema\/person\/a3304c209434f63c501b05622d7d2720"},"headline":"Manage transactions with Spring @Transactional","datePublished":"2023-01-31T05:25:33+00:00","dateModified":"2024-02-03T16:21:05+00:00","mainEntityOfPage":{"@id":"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/"},"wordCount":1626,"commentCount":0,"publisher":{"@id":"https:\/\/thoaicoder.com\/#\/schema\/person\/a3304c209434f63c501b05622d7d2720"},"keywords":["Java","Spring","Transactional"],"articleSection":["Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/","url":"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/","name":"Manage transactions with Spring @Transactional - I \u2764 Code","isPartOf":{"@id":"https:\/\/thoaicoder.com\/#website"},"datePublished":"2023-01-31T05:25:33+00:00","dateModified":"2024-02-03T16:21:05+00:00","breadcrumb":{"@id":"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/thoaicoder.com\/index.php\/2023\/01\/31\/manage-transaction-with-spring-transactional\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/thoaicoder.com\/"},{"@type":"ListItem","position":2,"name":"Manage transactions with Spring @Transactional"}]},{"@type":"WebSite","@id":"https:\/\/thoaicoder.com\/#website","url":"https:\/\/thoaicoder.com\/","name":"I \u2764 Code","description":"","publisher":{"@id":"https:\/\/thoaicoder.com\/#\/schema\/person\/a3304c209434f63c501b05622d7d2720"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/thoaicoder.com\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/thoaicoder.com\/#\/schema\/person\/a3304c209434f63c501b05622d7d2720","name":"Thoai","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/thoaicoder.com\/#\/schema\/person\/image\/","url":"https:\/\/thoaicoder.com\/wp-content\/uploads\/2023\/03\/photo_2023-01-05_22-53-32.jpg","contentUrl":"https:\/\/thoaicoder.com\/wp-content\/uploads\/2023\/03\/photo_2023-01-05_22-53-32.jpg","width":640,"height":640,"caption":"Thoai"},"logo":{"@id":"https:\/\/thoaicoder.com\/#\/schema\/person\/image\/"},"sameAs":["https:\/\/thoaicoder.com","https:\/\/www.linkedin.com\/in\/huu-thoai-nguyen\/"],"url":"https:\/\/thoaicoder.com\/index.php\/author\/admin_cvyxq4b8\/"}]}},"_links":{"self":[{"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/posts\/84","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/comments?post=84"}],"version-history":[{"count":60,"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/posts\/84\/revisions"}],"predecessor-version":[{"id":812,"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/posts\/84\/revisions\/812"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/media\/139"}],"wp:attachment":[{"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/media?parent=84"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/categories?post=84"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thoaicoder.com\/index.php\/wp-json\/wp\/v2\/tags?post=84"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}