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

17,718

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

Share:
17,718

Related videos on Youtube

LifeStartsAtHelloWorld
Author by

LifeStartsAtHelloWorld

Updated on June 04, 2022

Comments

  • LifeStartsAtHelloWorld
    LifeStartsAtHelloWorld almost 2 years

    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.

    • M. Deinum
      M. Deinum over 6 years
      You aren't really clear (imho). Yes you need @Transactional when modifying data even with @Modifying that is only an annotation to let Spring Data know you have a @Query that changes stuff. The @Transactional marks the start AND end of a transaction. If you put it in your service layer everything called from within a single method participates in the same transaction. If you don't every call inside that single method will become its own transaction.
  • Timur Milovanov
    Timur Milovanov about 2 years
    I've found more precise quote "By default, CRUD methods on repository instances inherited from SimpleJpaRepository are transactional".