线程池中的Guice DAO提供程序 - 查询变为'在转换中空闲' [英] Guice DAO Provider in thread pool - queries become 'idle in transation'
问题描述
我使用Java 8,Hibernate 5.1.0.Final和Guice 4.1.0。
@Inject
私人提供者< 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();
$ b
每个 test()
方法执行会在 pg_stat_activity
中产生10个(线程池大小)行。它们很简单 select * from
具有空闲事务
状态并且永不消失的查询。所以我达到 hibernate.c3p0.max_size
限制,我的应用程序停止使用数据库。
数据库模块:
public class ExampleModule extends PrivateModule {
@Override
public void configure(){
install(new JpaPersistModule(example-persistence-unit)。properties(jpaProperties()));
bind(ExampleDAO.class).to(ExampleDAOImpl.class);
公开(ExampleDAO.class);
Key< PersistFilter> key = Key.get(PersistFilter.class,ExamplePersistenceUnit.class);
bind(key).to(PersistFilter.class);
揭露(关键);
我试过 @注入提供程序< ExampleDAO> exampleDAOProvider
放入任务类代码中,但它不会改变任何内容。如果我 @Inject exampleDAO
,那么我会遇到并发问题( ConcurrentModificationException
),因为它使用相同的 EntityManager
。
如果我使用 @Inject Provider< ExampleDAO>没有多线程的exampleDAOProvider
或者直接 @Inject ExampleDAO exampleDAO
,它运行良好,连接被释放。
为什么会发生?如何获得多线程代码中发布的连接?
我已经用 @注释了几乎所有的DAO方法Transactional
,这似乎解决了我的问题。处理完成后,交易将被提交并释放连接。没有标记为 @Transactional
方法,这些方法查询应在稍后保存在同一个 EntityManager
或<$ c中的实体$ c> Session 以避免使用 merge()
。请注意, @Transactional
仅适用于公共方法, synchronized
不适用于 @ Transactional
。
GenericDAOImpl使用 @Inject Provider< EntityManager>
代替
$ b $保护提供者< EntityManager> entityManagerProvider;
private EntityManager getEntityManager(){
return entityManagerProvider.get();
}
相关讨论: Guice Persist是否提供事务范围或应用程序管理的EntityManager?
UDPATE 1
另一件事要检查:
- 如果您使用Hibernate 5.1.0.Final,那么persistence.xml应该包含:
< property name =hibernate.connection.provider_classvalue =org.hibernate.c3p0.internal.C3P0ConnectionProvider/>
而不是:
< property name =connection.provider_classvalue =org.hibernate.connection.C3P0ConnectionProvider/>
UDPATE 2
如果您使用
< property name =hibernate.enable_lazy_load_no_transvalue =tru e/>
延迟加载时可能导致连接泄漏。相关讨论:
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?
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
这篇关于线程池中的Guice DAO提供程序 - 查询变为'在转换中空闲'的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!