jpa2 reuses entityManager with guice
Asked Answered
S

1

6

I have a web application that has some strange behavior where I can't really put my finger on. The core of my problem is that there is an inconsistent behavior in the values returned by my rest endpoints. When I start my application, my query returns the same values each time I call this endpoint. When I update an entity, my entity manager starts behaving oddly. Now my query starts returning different results. One time it returns old values instead of the values that are in the database or my result list contains proxies instead of objects (mixed). enter image description here

I have validated that my @transaction methods are placed correctly and in my debug stack I see the transaction interceptor and the entity manager is created per request to the backend (so no guice persistence filter)

My feeling indicates that the problem lies in the session context. I have the feeling (but I can't really grasp it) that it reuses my persistence context over multiple requests.

I have put some frameworks together to make this all work. I use resteasy as jax-rs implementor. guice (4.0beta4) as cdi implementor and hibernate as jpa implementor. Because we need to use a provider when we inject the entitymanager (since the entitymanager is created each transaction), I have wrapped this in a EntityManagerProxy. This class implements the EntityManager interface and delegates all methods to provider.get().method().

public class EntityManagerProxy implements EntityManager {
    private final Provider<EntityManager> entityManagerProvider;

    @Inject
    public EntityManagerProxy(final Provider<EntityManager> entityManagerProvider) {
        this.entityManagerProvider = entityManagerProvider;
    }

    private EntityManager getEntityManager() {
        return entityManagerProvider.get();
    }

    @Override
    public void persist(final Object entity) {
        getEntityManager().persist(entity);
    }
}

My guice module looks like this

public class OptiWEEEModule extends ServletModule implements Module {
    @Override
    protected void configureServlets() {

        super.configureServlets();
        bind(EntityManagerProxy.class);
        // JPA
        install(new JpaPersistModule("myPU"));
    }
}

I know this is a vague issue, but could someone help me in the right direction? This isn't really an issue I can provide a error message for.

edit: I now pin pointed the problem. With a profiler i looked an the entitycontext is reused by guice. This means it doesn't every time execute the query, but uses the existing entity manager, which should be created each time a @transactional annotation is passed.

Stretcher answered 6/5, 2014 at 19:37 Comment(5)
I just downgraded from guice 4beta4 to guice 3 and the same error occurs.Stretcher
The idea of @Transactional that you get a new transaction, not a new EntityManager. The latter can handle few of those just as well. You don't show the "update" part of your proxy nor the webservices, so it's hard to say what's actually causing your issue.Pennsylvanian
I actually drilled down the problem. Not the update part break my application, but the entitymanager is reused on each thread. I guess I'm creating a singleton that holds my entitymanager. Could my entitymanagerproxy be causing this? this is the strategy I'm following code.google.com/p/google-guice/wiki/…Stretcher
This question sounds similar.Pennsylvanian
@Pennsylvanian The question is very similiar indeed, but I'm already injecting a provider at each pointStretcher
S
1

I got this awnser from the mailing lists.

Guice perstist has a feature which is rather unusual und causes some problems. I think you might just be hitting it

When you request an entity manager outside of a unit of work guice persist will implicitly start the unit of work for you. Unfortunately the isActive() on UnitOfWork is package private. And you cannot test if a unit of work is active.

There are two ways to explicitly start and end a unit of work. You can use the UnitOfWork and the methods begin() and end(). Also the @Transactional annotation starts a unit of work. @Transactional will also end the unit of work if and only if it started it.

It is best practice to only obtain an entity manager within a @Transactional method.

I can only conclude that the @Transaction annotation isn't of the same maturity level as the one in spring. On the other hand getting the entity manager within an @Transactional manager via a provider doesn't really solve this problem.

Since we are moving to production really soon, I have switched back to spring, which is a shame, but was the only sensible solution to manage our deadline.

Stretcher answered 18/6, 2014 at 6:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.