2

I use Java 8, Hibernate 5.1.0.Final and Guice 4.1.0.

@Inject
private Provider<ExampleDAO> exampleDAOProvider;

public void test(){

    ExecutorService threadPool = Executors.newFixedThreadPool(10);

    for (int i = 0; i < 100; i++)
        threadPool.execute(new Runnable() {

            @Override
            public void run() {
                logger.info(exampleDAOProvider.find(1l));

            }
        });

    threadPool.shutdown();

}

Every test() method execution will produce 10 (thread pool size) rows more in pg_stat_activity. They are simple select * from queries which have idle in transaction state and never disappear. So I reach hibernate.c3p0.max_size limit and my application stops working with database.

Database module:

public class ExampleModule extends PrivateModule {

    @Override
    public void configure() {

        install(new JpaPersistModule("example-persistence-unit").properties(jpaProperties()));

        bind(ExampleDAO.class).to(ExampleDAOImpl.class);

        expose(ExampleDAO.class);

        Key<PersistFilter> key = Key.get(PersistFilter.class, ExamplePersistenceUnit.class);
        bind(key).to(PersistFilter.class);
        expose(key);
    }
}

I have tried to @Inject Provider<ExampleDAO> exampleDAOProvider into the task class code but it does not change anything. If I @Inject exampleDAO, then I face concurrency issues (ConcurrentModificationException) because it uses the same EntityManager.

If I use @Inject Provider<ExampleDAO> exampleDAOProvider or direct @Inject ExampleDAO exampleDAO without multithreading, it works well and connections get released.

Why does it happen? How to get connections released in the multithreaded code?

Justinas Jakavonis
  • 6,374
  • 5
  • 52
  • 88

1 Answers1

0

I have annotated almost every DAO method with @Transactional and this seems to solve my problem. After processing, transactions are committed and connections released. Didn't mark as @Transactional methods which query entities which should be persisted later in the same EntityManager or Session to avoid using merge(). Please note that @Transactional works only for public methods and synchronized doesn't work with @Transactional.

GenericDAOImpl use @Inject Provider<EntityManager> instead of @Inject EntityManager:

@Inject
protected Provider<EntityManager> entityManagerProvider;

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

Related discussion: Does Guice Persist provide transaction scoped or application managed EntityManager?


UDPATE 1

Another things to check:

  • If you're using Hibernate 5.1.0.Final, then persistence.xml should contain:

<property name="hibernate.connection.provider_class" value="org.hibernate.c3p0.internal.C3P0ConnectionProvider" />

Instead of:

<property name="connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider" />

UDPATE 2

If you're using

<property name="hibernate.enable_lazy_load_no_trans" value="true" />

it may cause connection leaks when lazy loading. Related discussions:

Justinas Jakavonis
  • 6,374
  • 5
  • 52
  • 88