views:

54

answers:

2

There are 19 methods in our DAO layer, each is some variation of this:

public TicketProp saveTicketProp(TicketProp prop) {
    EntityManager em = this.emf.createEntityManager();
    try {
        em.getTransaction().begin();
        prop = (TicketProp) em.merge(prop);
        em.getTransaction().commit();
        return prop;
    } finally {
        em.close();
    }
}

Meaning: In each method we handle our own transaction and close it in a finally block. We're testing a Jersey app, so our JUnit tests extend JerseyTest. Each test method instantiates a Grizzly container, runs the test, then shuts down the container. EntityManagerFactory is injected by spring. We're using JPA over Hibernate.

I'm monitoring the connections to our MySQL test DB and they're always high. One test alone runs the MySQL "Max_used_connections" variable to 38. For fun, I went and commented out all the em.close() calls, and the test still uses 38 connections.

I'm using Hibernate's built-in connection pooling (not for prod use, I know). I still expected some sort of intelligent pooling.

Am I handling the EntityManager wrong? How else can I close connections?

+1  A: 

Why do you think that EntityManager.close() always physically closes underlying connection? It's up to connection pool (you probably need to configure it and set the maximum number of simultaneously open connections).

a1ex07
+1  A: 

You should close the EntityManagerFactory at the end of your test. From the javadoc of EntityManagerFactory#close():

void javax.persistence.EntityManagerFactory.close()

Close the factory, releasing any resources that it holds. After a factory instance has been closed, all methods invoked on it will throw the IllegalStateException, except for isOpen, which will return false. Once an EntityManagerFactory has been closed, all its entity managers are considered to be in the closed state.

As a side note, you should actually rollback the transaction before closing the EM in the finally clause:

public TicketProp saveTicketProp(TicketProp prop) {
    EntityManager em = this.emf.createEntityManager();
    try {
        em.getTransaction().begin();
        prop = (TicketProp) em.merge(prop);
        em.getTransaction().commit();
        return prop;
    } finally {
        if (em.getTransaction().isActive()) {
            em.getTransaction().rollback();
        }

        if (em.isOpen()) {
            em.close();
        }
    }
}
Pascal Thivent
Transactions won't automatically be rolled back in the event of an Exception? Is my finally block preventing that?
gmoore
@gmoore: In case of a JPA exception, yes. But what about others? I consider calling rollback in the finally block to be a good practice.
Pascal Thivent