I am using spring boot 1.2.3.RELEASE version with JPA over hibernate. I am experiencing following exception
org.springframework.dao.InvalidDataAccessApiUsageExce
First, I make a quote of the Spring-Data JPA Documentation to justify why the delete
method works in your case (I mean the option 2).
CRUD methods on repository instances are transactional by default. For reading operations the transaction configuration
readOnly
flag is set to true, all others are configured with a plain@Transactional
so that default transaction configuration applies. For details see JavaDoc of CrudRepository
The delete
method is actually a method of the CrudRepository
. Your repository extends JpaRepository
which extends CrudRespository
, so it belongs to CrudRepository interface and according the quote above is transactional.
If you read the section Transactional Query Method you will see that is the same that the option 4 and you will know how to apply a custom transactional behavior for all methods of your repository. Also, the Example 61 of the documentation shows the same scenario that the option 3.
Now keep in mind that you aren't working with JDBC logic, in which case the database take care about the transactions, but within a ORM-based framework. ORM frameworks require a transaction in order to trigger the synchronization between the object cache and the database.
So you must be aware and provide a transaction context for methods that do ORM logic like deleteByCustomerId
.
By default @Transactional
(I mean without any parameter) set propagation mode to REQUIRED
and readOnly flag to false. When you invoke a method annotated within, a transaction is intialized if no-one exists. This is the reason of why the workaround of @LucasSaldanha (the same as example Using a facade to define transactions for multiple repository calls) and the option 4 works. Other wise, without a transaction, you fall in the thrown exception of the option 1.
Ok I found out a way of making it works.
Just put a @Transactional
annotation (org.springframework.transaction.annotation.Transactional) in your deleteOrder method at OrderService.
@Transactional
public void deleteOrder(long customerId){
repo.deleteByCustomerId(customerId);
}
I really don't know why the second works. I guessing that since it is an direct method from the CrudRepository interface someway it knows how to execute it atomically.
The former one is a call to the deleteByCustomerId. This call will be processed to find out the customer with the specified id and then deletes it. For some reason it makes the use of an explicit transaction.
Again it is just a guess. I'll try to contact some spring developers and maybe open a issue to verify this behaviour.
Hope it helps!
Reference: http://spring.io/guides/gs/managing-transactions/
I still got the No transactional EntityManager available
exception even after annotating my search()
method with @Transactional
.
I followed this tutorial which describes how to set up Hibernate search in Spring Boot.
The issue for me was that I had a different dependency on hibernate-search-orm
. The dependency which worked for me without any problems was
compile("org.hibernate:hibernate-search-orm:5.7.0.Final")
After adding this to the gradle build file, everything worked as expected.
Hope this helps someone else as well.