线程池中的 Guice DAO 提供程序 - 查询变为 'idle in transation'
Guice DAO Provider in thread pool - queries become 'idle in transation'
我使用 Java 8、Hibernate 5.1.0.Final 和 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();
}
每个 test()
方法执行将在 pg_stat_activity
中产生 10(线程池大小)行。它们是具有 idle in transaction
状态且永不消失的简单 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);
expose(ExampleDAO.class);
Key<PersistFilter> key = Key.get(PersistFilter.class, ExamplePersistenceUnit.class);
bind(key).to(PersistFilter.class);
expose(key);
}
}
我已经尝试 @Inject Provider<ExampleDAO> exampleDAOProvider
进入任务 class 代码,但它没有改变任何东西。如果我 @Inject exampleDAO
,那么我会面临并发问题 (ConcurrentModificationException
),因为它使用相同的 EntityManager
.
如果我在没有多线程的情况下使用 @Inject Provider<ExampleDAO> exampleDAOProvider
或直接 @Inject ExampleDAO exampleDAO
,它运行良好并且连接被释放。
为什么会这样?如何在多线程代码中释放连接?
我几乎用 @Transactional
注释了每个 DAO 方法,这似乎解决了我的问题。处理后,提交事务并释放连接。没有标记为 @Transactional
查询实体的方法,这些实体稍后应该在相同的 EntityManager
或 Session
中保留以避免使用 merge()
。请注意,@Transactional
仅适用于 public 方法,而 synchronized
不适用于 @Transactional
。
GenericDAOImpl 使用 @Inject Provider<EntityManager>
而不是 @Inject EntityManager
:
@Inject
protected Provider<EntityManager> entityManagerProvider;
private EntityManager getEntityManager() {
return entityManagerProvider.get();
}
相关讨论:Does Guice Persist provide transaction scoped or application managed EntityManager?
UDPATE 1
要检查的其他事项:
- 如果您使用的是 Hibernate 5.1。0.Final,则 persistence.xml 应包含:
<property name="hibernate.connection.provider_class" value="org.hibernate.c3p0.internal.C3P0ConnectionProvider" />
而不是:
<property name="connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider" />
UDPATE 2
如果您正在使用
<property name="hibernate.enable_lazy_load_no_trans" value="true" />
延迟加载时可能会导致连接泄漏。相关讨论:
- org.hibernate.LazyInitializationException - could not initialize proxy - no Session
- Solve Hibernate Lazy-Init issue with hibernate.enable_lazy_load_no_trans
我使用 Java 8、Hibernate 5.1.0.Final 和 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();
}
每个 test()
方法执行将在 pg_stat_activity
中产生 10(线程池大小)行。它们是具有 idle in transaction
状态且永不消失的简单 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);
expose(ExampleDAO.class);
Key<PersistFilter> key = Key.get(PersistFilter.class, ExamplePersistenceUnit.class);
bind(key).to(PersistFilter.class);
expose(key);
}
}
我已经尝试 @Inject Provider<ExampleDAO> exampleDAOProvider
进入任务 class 代码,但它没有改变任何东西。如果我 @Inject exampleDAO
,那么我会面临并发问题 (ConcurrentModificationException
),因为它使用相同的 EntityManager
.
如果我在没有多线程的情况下使用 @Inject Provider<ExampleDAO> exampleDAOProvider
或直接 @Inject ExampleDAO exampleDAO
,它运行良好并且连接被释放。
为什么会这样?如何在多线程代码中释放连接?
我几乎用 @Transactional
注释了每个 DAO 方法,这似乎解决了我的问题。处理后,提交事务并释放连接。没有标记为 @Transactional
查询实体的方法,这些实体稍后应该在相同的 EntityManager
或 Session
中保留以避免使用 merge()
。请注意,@Transactional
仅适用于 public 方法,而 synchronized
不适用于 @Transactional
。
GenericDAOImpl 使用 @Inject Provider<EntityManager>
而不是 @Inject EntityManager
:
@Inject
protected Provider<EntityManager> entityManagerProvider;
private EntityManager getEntityManager() {
return entityManagerProvider.get();
}
相关讨论:Does Guice Persist provide transaction scoped or application managed EntityManager?
UDPATE 1
要检查的其他事项:
- 如果您使用的是 Hibernate 5.1。0.Final,则 persistence.xml 应包含:
<property name="hibernate.connection.provider_class" value="org.hibernate.c3p0.internal.C3P0ConnectionProvider" />
而不是:
<property name="connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider" />
UDPATE 2
如果您正在使用
<property name="hibernate.enable_lazy_load_no_trans" value="true" />
延迟加载时可能会导致连接泄漏。相关讨论:
- org.hibernate.LazyInitializationException - could not initialize proxy - no Session
- Solve Hibernate Lazy-Init issue with hibernate.enable_lazy_load_no_trans