Guice DAO provider in thread pool - requests become “inactive in transaction”

I am using 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(); } 

Each execution of the test() method will create 10 (thread pool size) more in pg_stat_activity . These are simple select * from queries that have an idle in transaction state and never disappear. Therefore, I reach the limit of hibernate.c3p0.max_size , and my application stops working with the 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 tried @Inject Provider<ExampleDAO> exampleDAOProvider to enter the task class code, but didn't change anything. If I @Inject exampleDAO , then I am facing concurrency ( ConcurrentModificationException ) problems because it uses the same EntityManager .

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

Why is this happening? How to get connections released in multi-threaded code?

+2
source share
1 answer

I wrote almost every DAO method using @Transactional and this seems to solve my problem. After processing, transactions are completed and connections are released. It is not marked as @Transactional methods that request objects that must be stored later in the same EntityManager or Session to avoid using merge() . Please note: @Transactional only works for public methods, while synchronized does not 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 a transaction or application-driven EntityManager?


UDPATE 1

One more thing to check:

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

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

Instead:

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

UDPATE 2

If you use

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

it may cause connection leakage during lazy loading. Related discussions:

0
source

Source: https://habr.com/ru/post/1268172/


All Articles