Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do we need both @Transactional and @Modifying annotation in Spring?

I am still trying to wrap my head around how @Transactional works.

I have @Transactional annotation on Service class's method and @Modifying annotation on the method in the Repository class. Does method with @Transactional annotation applies to the method in the Repository with annotation @Modifying?

My understanding:

@Transactional on a method of a class with @Transactional( readOnly = true ) no data gets written to the database, whereas with @Transactional, the data gets written to the database.

Modifying Queries

  1. Modifying method signature can only return void, Integer or int
  2. Updating queries MUST be transactional, mark with @Transactional
  3. Spring Data will drop all non-flushed changes pending in the EntityManager, change with @Modifying(clearAutomatically=false)

As the second point says @Modifying queries must have @Transactional(readOnly=false), so we can either add it at @Service level method call or @Repository method level call. If added at the @Service level it applies to the @Respository method too which is being called from the @Service level method call?

Example:

@Service
class AnimalServiceImpl implements AnimalService {

@Autowire
AnimalRepository animalRepository;

@Override
@Transactional
public void persistAnimal() {
....
animalRepository.save();
}

@Override
@Transactional(readOnly = true)
public void checkIfAnimalPresent() {

...
animalRepository.checkIfPresent();

}

@Override
@Transactional
public void deleteAnimal() {
...
animalRepository.deleteAnimal();
}
}

Repository

@Repository
@Transactional(readOnly=true)
public interface AnimalRepository extends org.springframework.data.repository.Repository {

@Modifying
@Query(...)
void save();

@Modifying
@Query(...)
int checkIfPresent() 

@Modifing
@Query(..)
int deleteAnimal();
}

My question is around:

  1. Why do we need @Transactional in the service class when we have it at the repository @Repository level and I have @Modifying on methods which modify the entity and writes it to the database (only because I have @Transactional(readOnly = true) at the class level) ?
  2. Does the annotation @Transactional on the Service class propogate to @Repository class?

I hope I am very clear with my questions and examples here.

like image 459
LifeStartsAtHelloWorld Avatar asked Jan 18 '18 05:01

LifeStartsAtHelloWorld


People also ask

Is @transactional required?

REQUIRED is the default setting of a @Transactional annotation. The REQUIRED propagation can be interpreted as follows: If there is no existing physical transaction, then the Spring container will create one.

Is it sufficient to annotate the classes with the @transactional annotation?

It is not sufficient to tell you simply to annotate your classes with the @Transactional annotation, add the line ( <tx:annotation-driven/> ) to your configuration, and then expect you to understand how it all works.

What is the use of @modifying annotation?

The @Modifying annotation is used to enhance the @Query annotation so that we can execute not only SELECT queries, but also INSERT, UPDATE, DELETE, and even DDL queries.

Why @transactional annotation is used in Spring?

The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.


1 Answers

This how @Transactional works:

By default, CRUD methods on repository instances are transactional.
For read operations, the transaction configuration readOnly flag is set to true.
All others are configured with a plain @Transactional so that default transaction configuration applies.
If you need to tweak transaction configuration for one of the methods declared in a repository you can override that method and add @Transactional annotation with required attribute values.

Another way to alter transactional behavior is to use a facade or service implementation that (typically) covers more than one repository.
Its purpose is to define transactional boundaries for non-CRUD operations.

If you use this approach, the transaction configuration at the repositories is then neglected, as the outer transaction (defined in the service layer) configuration determines the actual one used.

Reference: Spring Data JPA - Reference Documentation - 5.7. Transactionality

like image 158
Lokesh Kollamgunta Avatar answered Oct 29 '22 09:10

Lokesh Kollamgunta