【问题标题】:Keeping JPA EntityManager open - Connection Pooling保持 JPA EntityManager 打开 - 连接池
【发布时间】:2015-09-14 17:42:01
【问题描述】:

在我们开发的一项 RESTful Web 服务 (Spring MVC - Rest) 中,我们对数据库进行了大约 50 次调用。这大约需要一分钟才能完成。我们可以看到,在每次调用之后,JPA 实体管理器都会关闭并创建一个新的,如下面的日志所示

DEBUG o.s.o.jpa.EntityManagerFactoryUtils - Closing JPA EntityManager
17:18:16.399 [http-bio-8080-exec-5] DEBUG o.s.o.j.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler - Creating new EntityManager for shared EntityManager invocation

我们怀疑这需要时间,因为查询单独执行时需要的时间最短。我们如何确保 JPA 连接始终保持打开状态?请注意,这是一个 GET 调用,我们没有进行任何更新。我们如何实现连接池? JPA 连接的关闭\打开这么贵吗?

这是我们以编程方式声明 EntityManager (ApplicationConfiguration)

    LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
    entityManagerFactory.setDataSource(dataSource());
    entityManagerFactory.setPersistenceProviderClass(HibernatePersistence.class);
    entityManagerFactory.setPackagesToScan("com.skyteam.api.flightstatus.domain.persistence");
    Properties properties = new Properties();
    properties.put("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
    properties.put("hibernate.show_sql", "true");
    properties.put("hibernate.show_sql", "true");properties.put("hibernate.show_sql", "true");

我尝试过以下使用休眠的 c3p0 进行连接池,但没有帮助。

properties.put("hibernate.c3p0.min_size", "5");
properties.put("hibernate.c3p0.max_size", "20");
properties.put("hibernate.c3p0.timeout", "300");
properties.put("hibernate.c3p0.max_statements", "50");
properties.put("hibernate.c3p0.idle_test_period.timeout", "3000");

有什么帮助吗? (注意 - 之前看起来相似的问题没有帮助)

【问题讨论】:

  • dataSource()方法的post内容

标签: spring hibernate jpa spring-data connection-pooling


【解决方案1】:

您似乎是在方法dataSource() 中创建数据源。

我相信,你有两个选择:

  1. 将该数据源包装到ComboPooledDataSource。它也是 实现javax.sql.DataSource 接口并将池添加到 数据库连接。
  2. 不要显式创建数据源,而是让 JPA 创建它。 像这样的:

    properites.put("javax.persistence.jdbc.driver","...");
    properites.put("javax.persistence.jdbc.url","...");
    properites.put("javax.persistence.jdbc.user","...");
    properites.put("javax.persistence.jdbc.password","...");
    

【讨论】:

  • 真的非常感谢您的回答!解决了我的问题。你能解释一下为什么显式创建数据源会导致这个问题吗?
  • 因为 Spring Boot 提供的默认数据源默认使用连接池(假设您在类路径上有连接池库)。