This forum is now a read-only archive. All commenting, posting, registration services have been turned off. Those needing community support and/or wanting to ask questions should refer to the Tag/Forum map, and to http://spring.io/questions for a curated list of stackoverflow tags that Pivotal engineers, and the community, monitor.

AnnouncementAnnouncement Module

Collapse

No announcement yet.

entityManager not suspended when @Transactioanl( REQUIRES_NEW )Page Title Module

entityManager not suspended when @Transactioanl( REQUIRES_NEW )

Apr 8th, 2011, 09:44 AM

I'm looking for a way to have Spring bind a new entityManager in the EntityManagerHolder for methods marked @Transactional( propagation = Propagation.REQUIRES_NEW ) suspending the existing one if it exists. I'm also surprised that this isn't the default behavior. Let me explain why:

First my general setup: I'm using the OpenEntityManagerInViewFilter to make an entityManager available throughout a request. Controller methods that save changes are marked @Transactional( REQUIRED ). These methods cause the entityManager opened by the filter to by associated to the transaction, so that when the transaction commits, the entityManager is flushed, but stays around for the rest of the request. Everything is as expected.

Now comes the problem. I have an exception handler setup to log unexpected errors that occur in controller methods to the database. Here's it is:

The problem is that the @Transactional( REQUIRES_NEW ) doesn't cause a new entityManager to be created, but rather uses the entityManager opened by the filter just like @Transactional( REQUIRED ). Here's a use case when this fails to work properly:

2 - the commit causes a validation exception to be thrown, the transaction is rolled back.
3 - the exception handler is called because of this (REQUIRES_NEW), and persists an entity about the error.
4 - the exception handler's transaction commits, but since it's using the same entityManager, which still contains the invalid entity, it also causes a validation exception to be thrown, and is also rolled back!

It seems I really should be getting a new entityManager when propagation = REQUIRES_NEW! Is there some way to tell Spring to behave like this or some other way (preferably not a hack, I got that covered already!) to accomplish what I want?

No you shouldn't be getting e new entitymanager with the propagation level is REQUIRES_NEW, this would introduce a whole lot of issues...

If you need a new/fresh not related EntityManager create one yourself, which is what I would always do in an exceptionhandler, because in case of an exception the state of the entitymanager isn't reliable anymore , so you always want a fresh one. (This is at least the case for hibernate).

Comment

No you shouldn't be getting e new entitymanager with the propagation level is REQUIRES_NEW, this would introduce a whole lot of issues...

If you need a new/fresh not related EntityManager create one yourself, which is what I would always do in an exceptionhandler, because in case of an exception the state of the entitymanager isn't reliable anymore , so you always want a fresh one. (This is at least the case for hibernate).

Comment

@Marten - Thank you for your reply. There's something I don't understand though. From my point of view, not getting a new entityManager introduces issues:

REQUIRES_NEW states the intention to get a clean slate. The callee doesn't want to inherit the caller's transaction, nor does it want to inherit its entityManager. The actual behavior however is sometimes like this, but not always, it depends on the caller's context:

If the caller's context is transactional: the existing transaction and entityManager are suspended, new ones are created for the callee

If the caller's context is not transactional: a new transaction is created, but the entityManager of the caller is inhertied by the callee.

In effect, the callee receives a new entityManager only if the caller is transactional. This is not a clean slate! The use case of the exceptionHandler shows how this can be a problem.

Your suggestion of creating a new entityManager to address the problem is what I'm looking for. I'd expect Spring to do this by default however, but I will explore doing this myself if all else fails. But if this was the default behavior, what is it you're thinking of that would be problematic? Can you describe a sample use case that would break?

Comment

Thank you once again. I don't doubt you're right that this would break the contract. I'm not trying to gets the specs revised, just trying to understand and find a clean way to get what I want. So here's what I have in mind:

My DAOs all inherit from a base DAO class that injects the persistence context like this:

So to setup a "clean slate" context and continue to use my DAOs, I have to change the context's entityManager (and JDBC connection to be complete, thanks for pointing that out). I don't think I can simply create a new entityManager in the callee: this won't change the fact that the caller's entityManager will already have been bound to the transaction, causing it to roll back.

So I'm left with one other option: push the requirement on the caller to cleanup their context before the call. This works:

So there's a read-only transaction setup to absorb the caller's context, which gets suspended when calling the desired method, finally setting up a clean context. This works but it's rather hacky, and imposes a constraint on the caller which I'd like to avoid. Do you know a better way?