Guice DAO Provider in thread pool - queries become 'idle in transation'

蓝咒 提交于 2019-12-14 02:07:23

问题


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?


回答1:


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:

  • org.hibernate.LazyInitializationException - could not initialize proxy - no Session
  • Solve Hibernate Lazy-Init issue with hibernate.enable_lazy_load_no_trans


来源:https://stackoverflow.com/questions/43919411/guice-dao-provider-in-thread-pool-queries-become-idle-in-transation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!