This post is about a recent problem I ran into using custom update queries in an application using Spring Data. I’ve had success with this in the past but this time I was trying to call the repository method directly from a lambda passed in a Spring Integration flow definition like so:
IntegrationFlows.from("myChannel") ... .handle(Integer.class, (p, h) -> { myEntityRepository.setSuccessForEntity(p); return p; }) ...
The Problem
In the application I was using @Query
to specify a custom update statement in the repository.
@Repository public interface MyEntityRepository extends CrudRepository<MyEntity, Integer>{ @Modifying @Query("update MyEntity e set e.status = 1 where e.parentId = ?1") int setSuccessForEntity(int parentId); }
Trying to use this method resulted in:
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
It appears that calling the repository as I was from the lambda was not properly starting a transaction. My first attempt to fix was to add @Transactional
to the repository method. This gave the same exception. Without actually digging too deep into it my guess is that the transactional behavior was getting lost in some double proxying somewhere during the creation/invocation of the repository implementation.
The Fix
To get around this problem I ended up creating a new service class to wrap the repository and annotated the service methods as @Transactional.
@Component public class MyEntityService { @Autowired private MyEntityRepository myEntityRepository; @Transactional public void markSuccess(int parentId){ myEntityRepository.setSuccessForEntity(parentId); } }
I now use this service in my service activator instead of the repository directly.
Thanks!!!! It works.
LikeLike
Nice, Estube buscando por que ocurria el problema y como solucionarlo por horas.:)
LikeLike
En el repositorio tambien trabaja, in the repository it work too.
LikeLike