【问题标题】:spring boot connection pool with long running requests具有长时间运行请求的 Spring Boot 连接池
【发布时间】:2018-10-22 07:38:46
【问题描述】:

当一个spring boot请求启动时,它会从池中获取一个连接。我的问题是 - 这个连接是否仍然与请求线程绑定(即使它没有执行任何查询)并且只在请求完成时返回到池中?

例如,如果我正在做类似的事情:

  1. 请求开始
  2. 执行查询(20 毫秒)
  3. 调用外部http服务(1500ms)
  4. 请求完成

这个请求线程获得的连接会在20ms还是1520ms内一直被线程占用(对其他请求不可用)?

PS:我正在使用带有 HikariCP 的 Spring Boot 2.0,但我没有使用 @Transactional。

谢谢。

【问题讨论】:

  • 池中的连接将用于每个事务而不是每个请求,我认为查询(20ms)执行事务的线程将使用连接执行,并在事务获得后返回池完成,
  • 是否在请求开始时从池中获取连接取决于您的设置。如果您使用 JPA 并且没有更改默认值,则为 true,它将在请求开始时获取并在结束时返回到池中。如果没有,将为每个被调用的顶级@Transactional 方法获取连接。所以这实际上取决于。

标签: spring spring-boot hikaricp


【解决方案1】:

如果你的类路径中有 Spring MVC,Spring 将自动配置一个 OpenEntityManagerInViewInterceptor 的实例(在 org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.JpaWebConfiguration 中),除非你将 spring.jpa.open-in-view 配置为 false。这个拦截器将打开一个EntityManager 的实例并将其绑定到TransactionSynchronizationManager 在整个请求期间。

这意味着在第一次使用存储库查询时,它将从池中借用一个连接并保持它直到EntityManager被拦截器关闭时请求结束。将连接返回到池是EntityManager 的责任。因此,在这种情况下,在您的示例中,连接将被借用 1520 毫秒。

如果您禁用spring.jpa.open-in-view 选项,则在您不使用任何显式事务的情况下,每次使用存储库查询时都会借用并返回一个连接。虽然这可能看起来更好,但您必须记住,您的实体的托管实例将需要在每个持久操作上系统地重新附加,因此可能会很昂贵。您还将失去EntityManager 缓存的好处。为避免这种情况,请使用事务来读取/修改/持久化您的实体并避免重新附加。

最后,请记住,如果您禁用spring.jpa.open-in-view,由于在请求期间您没有EntityManager,您需要确保您的延迟加载关系在事务中加载,否则你会得到可怕的LazyInitializationException

【讨论】:

    【解决方案2】:

    基本上取决于,

    如果您关闭连接,它将被释放回池中,并根据配置(如下)很快准备就绪,因此大约需要 20 毫秒(+ 回到池的时间)

    如果您不关闭连接,它将等到配置允许它,如果它允许无限期,理论上它可能会导致您的应用程序泄漏并且在应用程序关闭之前不会返回池。

    请参阅 answer 关于 Hikari 处理将连接返回到池的信息:

    Hikari 管家每 30 秒运行一次,它会关闭所有未使用且早于 maxLifetime 的连接。如果连接数超过 minimumIdle 数,管家将关闭空闲时间超过 idleTimeout 的连接。

    查看更多关于max life time of connection

    默认情况下,Oracle 不会强制连接的最大生命周期(在 JDBC 驱动程序端 (1) 和服务器端 (2) 都没有)。所以在这方面,“基础设施强加的连接时间限制”是+infinity

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-28
      • 1970-01-01
      • 1970-01-01
      • 2021-10-16
      • 2014-06-24
      • 2011-01-12
      • 2012-02-16
      • 2011-01-23
      相关资源
      最近更新 更多