JavaDream spring boot @Transactional Annotation in Spring Boot

@Transactional Annotation in Spring Boot

Hi all in this blog we ‘ll learn about @Transactional annotation in spring boot. If you are using spring boot you must heard about this annotation. @Transactional annotation in spring boot use to manage the ACID property.

ACID stands for (Atomicity Consistency Isolation Durability). Atomicity stands for either all success or nothing happen. Consistency stands for database always go from one valid state to another valid state. Isolation is the most important one it checks how transaction behaves when run concurrently. It should not effect each other while running concurrently. Last one is durability and it means ones the changes are done it’s permanent there is no way back.

We can use @Transactional annotation on class level as well as on method level. If we are using it on class level so all the public method of that class are eligible for transactional. And if we have any class annotated with @Transactional and method also annotated with @Transactional. In this case method transactional overrides the class level transactional setting in simple words method level transactional get the precedence.

Before going to know how to use @Transactional in spring boot let’s see where we must not use @Transactional annotation

As we know @Transactional is handled by proxy that is manage by AOP(Aspect oriented programming). So we have to make sure or we can say we have to much aware where @Transactional annotation not works. There are few scenario where @Transactionl not work and that are below:

  • We must not use @Transactional annotation on Private, Static and Final method.
  • If we are calling @Transactional method from same class it ‘ll not work. Make sure your calling class is different. It can be call if we inject same class using ApplicationContext and then call the method of same class but it’s not recommended and not the good approach.
  • It should not work with Spring Reactive or we can say @Transactional ‘ll not work with Spring boot webflux.
  • Make sure your method throws the exception if you handle the exception @Transactional annotation ‘ll not work. If you are catching your exception for some reasons, make sure you explicitly throw exception after completing your code logic.

There are some property that use by @Transactional annotation and they are as follow:

  • propagation
  • isolation
  • rollbackFor and rollbackForClassName
  • noRollbackFor and noRollbackForClassName
  • readOnly
  • timeout
  • value
@Transactional(
    value = "",               // Alias for transactionManager
    propagation = Propagation.REQUIRED,
    isolation = Isolation.DEFAULT,
    readOnly = false,
    timeout = -1,             // -1 means no timeout. If use 5 means 5 second
    rollbackFor = {},         // Exceptions that will trigger rollback
    rollbackForClassName = {},
    noRollbackFor = {},       // Exceptions that will NOT trigger rollback
    noRollbackForClassName = {}
)Code language: PHP (php)

Let’s understand each one by one.

Propagation

Propagation is the most important property of @Transactional annotation. It tell us how transaction happens. In simple words it tells how transaction works when one method that is already annotated with @Transactional annotation call the other method that is also annotated with @Transactional annotation. There are many type of propagation let’s describe them first. First three are most used type of propagation and below that are least use.

  • REQUIRED : It states if there is already a transaction join that else create the new transaction.
  • REQUIRED_NEW : It states suspend existing one and create the brand new transaction.
  • NESTED : It makes save point, when we use nested it create a save point and only rollback that portion instead of complete transaction.
  • SUPPORTS : It states if there is already a transaction join that else run without transaction like a normal method.
  • NOT_SUPPORTED : It states always terminate if any transaction is there and run non transactionally.
  • MANDATORY : It states method should always run inside transaction. If there is no transaction it throws IllegalTransactionStateException.
  • NEVER : It just opposite of MANDATORY. it states that method should always run non transactionally. If there is any transaction exist it throws IllegalTransactionStateException.

Isolation

Isolation is one of the best property for transaction. We can say after propagation the next important property of @Transactional is isolation. It generally helps us to define how and when changes done by one thread is visible to other thread. Means when we are working in concurrent scenario how transaction data behaves.

Let’s see type of isolation and what problem it solves.

Follow below table.

Yes: Problem Exist with given isolation level.

No: Problem not exist for given isolation level.

Isolation LevelDirty ReadNon-Repeatable ReadPhantom Read
READ_UNCOMMITTEDYesYesYes
READ_COMMITTEDNoYesYes
REPETABLE_READNoNoYes
SERIALIZABLENoNoNo

Let’s understand what is Dirty Read, Non-Repeatable Read and Phantom Read.

Dirty Read: You can read the uncommitted data of other transaction. For example say two user working on same row for user table one for getting the username and other for updating the username. Say user1 updated the username column but do not commit the transaction. Now user2 come and read the username updated by user1 and displaying the updated name. Now some issue comes to user1 and he rollback the transaction. This is call the dirty read as user2 is displaying incorrect username.

Non-Repeatable Read: It suggest every time you get the different result for same query. Take the first example user2 get the username and in the same time user1 come and update the username and commit the transaction. So next time when user2 come for reading the same row it ‘ll return the different result.

Phantom Read: Phantom read suggest that we ‘ll get the different number of result while running the same query. Say user1 want to get all user that is present in user table so he run the select all query on this table and get the result. On the same time user2 come and delete or insert new row in the table. So when user 1 run query again he ‘ll get the different number of result.

So to overcome this situation we have to use the Isolation level property. Most commonly used one is READ_COMMITTED and some of the database like PostgreSQL, MySQL has this as default isolation level. But it’s totally depends upon your need. Say for bank balance update we must use REPETABLE_READ or SERIALIZABLE.

rollbackFor and rollbackForClassName

Spring @Transactional annotation by default rollback for unchecked (Runtime Exception) only. If your method that is annotated with @Transactional annotation throw any Checked exception like IOException or any custom exception then it do not rollback. If you want to rollback for this exception also then you need to use rollbackFor parameter of @Transactional annotation. Exception class must be present at compile time.

@Transactional(rollbackFor = IOException.class)Code language: CSS (css)

But if we don’t have class available at compile time then we need to use rollbackForClassName. Here we pass the class name as string.

@Transactional(rollbackForClassName = "com.example.MyCheckedException")Code language: CSS (css)

noRollbackFor and noRollbackForClassName

If we don’t want to rollback our transaction for some specific exception then we can use this parameter of @Transactional annotation. We can provide a exception or list of exception with this parameter. And whenever these exception occurs our transaction ‘ll not rollback.

noRollbackForClassName use when we don’t have class at compile time. We declare class here as string.

readOnly

This is the most use and most tricky parameter of @Transactional annotation. Most of the developer are confuse about this parameter like what’s the actual use of this. Let us clarify for you. We use this parameter to tell that this transaction should only for reading purpose we don’t want to delete or update anything here.

So does that mean we can’t do update and delete if use this parameter. No, you can as you allow to do any DB operation on this method. But generally for best practice if we are using this parameter we must not perform and insert, update or delete operation it should be for reading data only.

Now the confusion arises right one way we are saying that we use this parameter when we have to perform read only operation and other way we are saying that it do not prevent if you want to do any of the insert, update or delete operation but it’s not a good practice. So why we are using this and what issue it solves.

So the answer is when we use readOnly parameter so it reduce the overhead time and also avoid the dirty-checking. Dirty-checking is the concept of persistence-context or we can say first level cache. If we are using JPA then if we do any changes in Entity it’s tracked by persistence-context internally. Say you fetch a user data from user-detail table and after fetching you just update the mobileNumber and age value of the user entity but you haven’t call any save or persist operation. But once your method completed you ‘ll see that this value ‘ll be updated in DB.

It updated automatically because these changes are tracked by persistence-context. This is called the dirty-checking means without calling any save operation if there is any changes in entity it ‘ll automatically updated by persistence-context.

So if we use readOnly parameter then this dirty-checking ‘ll be avoided and data not update automatically by persistence-context.

timeout

This parameter suggest rollback the transaction if method do not committed in the specified timeout duration. So see below code snippet it suggest that if transaction take more than 5 second to complete just rollback automatically. If method completed after 5 seconds spring throws TransactionTimeOutException.

@Transactional(timeout = 5)Code language: CSS (css)

value

We use this parameter only when we are dealing with multiple Transaction manager. In other word we can say that it’s just an alias of TransactionManager. It tells spring which transactionManager bean needs to be use when we have multiple transactionManager.

If we are dealing with only one transactionManager we must not use this parameter.

Hope you like this blog. If you like this please share with other’s and help us to grow. You can provide your feedback in our comment section. If you need blog on any specific topic please mention in our comment section we ‘ll try to cover that in our upcoming blog.

Others blog you may like

How to deploy spring boot application on Kubernetes.

Redirect from http to https protocol using Nginx server

@MappedSuperClass annotation complete guide

Share with others

Related Post