线程池中的Guice DAO提供程序 - 查询变为'在转换中空闲' [英] Guice DAO Provider in thread pool - queries become 'idle in transation'

查看:168
本文介绍了线程池中的Guice DAO提供程序 - 查询变为'在转换中空闲'的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用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:

这篇关于线程池中的Guice DAO提供程序 - 查询变为'在转换中空闲'的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆