Do we need both @Transactional and @Modifying annotation in Spring?
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
Related videos on Youtube
LifeStartsAtHelloWorld
Updated on June 04, 2022Comments
-
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
- Modifying method signature can only return
void
,Integer
orint
- Updating queries MUST be transactional, mark with
@Transactional
- 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:
- 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) ? - 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 over 6 yearsYou 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.
- Modifying method signature can only return
-
Timur Milovanov about 2 yearsI've found more precise quote "By default, CRUD methods on repository instances inherited from SimpleJpaRepository are transactional".