1 quick question on Spring JPA repositories transactionality. I have a service that is not marked as transactional and calls Spring JPA repository method
userRegistrationRepository.deleteByEmail(email);
And it is defined as
@Repository public interface UserRegistrationRepository extends JpaRepository<UserRegistration, Long> { UserRegistration findByEmail(String email); void deleteByEmail(String email); }
The problem is that it fails with "No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call; nested exception is javax.persistence.TransactionRequiredException" exception.
Ok, I can solve it by marking the service or deleteByEmail(..) method as transactional, but I just can't understand why it crashes now. Spring documentation explicitly states that "CRUD methods on repository instances are transactional by default." (http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions), but apparently this one is not... So Is this statement related to only members of CrudRepository
?
ps: that's for Spring Data JPA 1.9.4
The usage of the @Repository annotation or @Transactional . @Repository is not needed at all as the interface you declare will be backed by a proxy the Spring Data infrastructure creates and activates exception translation for anyway.
The @Transactional annotation is the metadata that specifies the semantics of the transactions on a method. We have two ways to rollback a transaction: declarative and programmatic. In the declarative approach, we annotate the methods with the @Transactional annotation.
Commit a transaction by calling the commit() method on the Connection interface. This tells your database to perform all required consistency checks and persist the changes permanently. Rollback all operations performed during the transaction by calling the rollback() method on the Connection interface.
You are right. Only CRUD methods ( CrudRepository methods) are by default marked as transactional. If you are using custom query methods you should explicitly mark it with @Transactional annotation.
You are right. Only CRUD methods (CrudRepository
methods) are by default marked as transactional. If you are using custom query methods you should explicitly mark it with @Transactional
annotation.
@Repository public interface UserRegistrationRepository extends JpaRepository<UserRegistration, Long> { UserRegistration findByEmail(String email); @Transactional void deleteByEmail(String email); }
You should also be aware about consequences of marking repository interface methods instead of service methods. If you are using default transaction propagation configuration (Propagation.REQUIRED
) then:
The transaction configuration at the repositories will be neglected then as the outer transaction configuration determines the actual one used.
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
If you want more information about how it is implemented, take a look at default CrudRepository
/ JpaRepository
implementation - SimpleJpaRepository
(which you are probably using):
https://github.com/spring-projects/spring-data-jpa/blob/master/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java
The interesting lines are here:
@Transactional(readOnly = true) public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
and some of transactional methods here:
@Transactional public void deleteById(ID id) {
@Transactional public <S extends T> S save(S entity) {
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With