Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the proper way to ensure EntityManager connections are closed?

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?

like image 297
gmoore Avatar asked Jul 27 '10 21:07

gmoore


2 Answers

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();
        }
    }
}
like image 77
Pascal Thivent Avatar answered Oct 04 '22 17:10

Pascal Thivent


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).

like image 41
a1ex07 Avatar answered Oct 04 '22 16:10

a1ex07