Database transaction is a group of SQL statements that have to either success all or fail all, So that we can guarantee data consistency, As below image any break in the middle of these SQL statements will cause data inconsistency.
So you have to run these as a transaction, If any failure happen it will rollback all the changes and this provide Atomicity concept therefore transaction can not be divided (Any persistence tool have to provide Atomicity, Consistency, Isolation, Durability properties to it's system)
When you are using Spring Data JPA, you are using CrudRepository implementation that Spring gives you out of the box which build on top Hibernate framework which uses EntityManager class to deal with your database.
As EntityManager class, Any communication with database have to be done throw transaction as below example
And for reducing any boilerplate code regarding to begin transaction and commit it or rollback, Spring added @Transactionl annotation so that any method annotated with this will guarantee a lot of things mainly now beginning DB transaction and providing Atomicity to your logic.
But you may wondering about using JPA repositories in methods without adding @Transactional and it works, Yes you are right because JPA methods (save() , findById(id) .. ) their implementation already annotated with @Transactional which taking care of creating DB transaction if not exists.
Additionally, JPA methods like (save() , saveAll()) not perform any commit statements instead they just change the entity state in Persistence Context (EntityManager class), Then when transaction ends it performs flush operation that writes the records into DB then when closing the session commit statement is fired.
As a result, when you are using many JPA methods in one business logic method without @Transactional that means each JPA method will open it's own DB transaction and close it after finish, Therefore using JPA save() in loop may cause performance issue regarding to multiple open/close for transactions, In this case using saveAll() will be better.
@Trasnactional have propagation property with REQUIRED value as default which means in case of no transaction found start one, if there is one already found use it, So when using @Transactionl on your methods or services any inner JPA methods will use same transaction to deal with DB instead of creating one for each method.
There is more about propagation property and isolation as well, you can get more information resource section
At end of each transaction hibernate framework needs to know if it should fire any insert/update statements or not, So it fires dirty checking operation so it can know if there any entity changed and fire statement for it, so in case you have a methods with just retrieve operations it's better to set read-only property to true so you can avoid dirty checking operation (by default it has false value)
IF YOU LIKED THE POST, THEN YOU CAN SUPPPORT SUCH CONTENT WITH A CUP OF COFFEE, THANKS IN ADVANCE.