Reputation: 63
I have the following setup: Spring -> JPA -> Hibernate -> PostgreSQL
I've created a service layer which offers some "@Transactional" methods to insert data. The data is in the concrete case a person entity which has to be connected to a category entity (identifying relation) and some picture entities (non identifying relation).
As I have to offer a importer I've created a method (also @Transactional) to import a csv file. This method trys at first to insert the categories (which works well using em.persist() which is used from the DAO that is called by the service layer). Then I add a new person which becomes connected to the category I added before (the category gets loaded like it were already in the database -> HQL query), which also works as the category is persistent in the running transaction. The person entity also uses em.persist() to get persisted in the transaction.
Now I create the picture entities and connect them to the person entity. After connecting them, I also save the person, but as it is already persisted in the transaction I use em.merge(). Here I get a "EntityNotFoundException()" as hibernate (or jpa) could not load the category from the first step (it has a correct id, but it seems it couldn't see the transaction)...
All three methods insertCategory(), insertPerson() and addPicture() are also declared as @Transaction as they are used seperate in the normal use case. Maybe the problem is related to the nested Transaction, but it more seems to be related to the em.merge() as em.persist() runs well.
em is an EntityManager that gets injected from spring.
Any ideas what's going wrong?
Greetings Ben
Upvotes: 2
Views: 1422
Reputation: 2016
If you are using proxies (the Spring default of transaction handling) the @Transactional annotation is ignored when methods are being called within a class. The following will not work:
@Transactional
public void doStuff() {
this.doSomeOtherStuff();
}
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void doSomeOtherStuff() {
// do some more db work here.
}
If you are indeed doing this, you have two options:
You can read more about this in the Spring documentation here.
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.
Upvotes: 1