EntityManagerFactory.close() not closing HikariDataSource set by hibernate.connection.datasource-property

huangapple go评论78阅读模式
英文:

EntityManagerFactory.close() not closing HikariDataSource set by hibernate.connection.datasource-property

问题

I'll provide the translation of the code part:

fun main() {
    val emf = Persistence.createEntityManagerFactory("default", getJpaProperties())
    // Fetch underlying HikariDataSource
    val ds = emf.unwrap(SessionFactoryImpl::class.java)
        .serviceRegistry
        .getService<ConnectionProvider>(ConnectionProvider::class.java)
        .unwrap(HikariDataSource::class.java)
    emf.close()
    println(ds.isClosed) // prints "false"
}

private fun getJpaProperties(): Map<String, Any> {
    val dataSource = HikariDataSource().apply {
        username = "sa"
        password = ""
        jdbcUrl = "jdbc:h2:mem:test_db"
    }
    return mapOf(
        "hibernate.dialect" to "org.hibernate.dialect.H2Dialect",
        "hibernate.connection.datasource" to dataSource
    )
}

Let me know if you need anything else.

英文:

I'm using Hibernate 5.4.18 with HikariCP 3.4.5. My configuration is programmatic, and I set underlying DataSource of Hibernate with hibernate.connection.datasource-property. Strangely, when I then call EntityManagerFactory.close()-function, it doesn't call close()-method of HikariDataSource, and connection will leave open. Is this a desired behavior? Oracle documentation says that EntityManagerFactory.close() will "Close the factory, releasing any resources that it holds".

Minimum example with Kotlin:

fun main() {
    val emf = Persistence.createEntityManagerFactory(&quot;default&quot;, getJpaProperties())
    // Fetch underlying HikariDataSource
    val ds = emf.unwrap(SessionFactoryImpl::class.java)
        .serviceRegistry
        .getService&lt;ConnectionProvider&gt;(ConnectionProvider::class.java)
        .unwrap(HikariDataSource::class.java)
    emf.close()
    println(ds.isClosed) // prints &quot;false&quot;
}

private fun getJpaProperties(): Map&lt;String, Any&gt; {
    val dataSource = HikariDataSource().apply {
        username = &quot;sa&quot;
        password = &quot;&quot;
        jdbcUrl = &quot;jdbc:h2:mem:test_db&quot;
    }
    return mapOf(
        &quot;hibernate.dialect&quot; to &quot;org.hibernate.dialect.H2Dialect&quot;,
        &quot;hibernate.connection.datasource&quot; to dataSource
    )
}

答案1

得分: 1

这是因为您提供了数据源的实例。如果您初始化了一个数据源,那么在代码的其他部分很可能会使用它,因此关闭数据源会引入意外的行为。这实际上是一个良好的做法,即创建资源的“模块”也负责处理它的释放。

如果您提供了数据源的详细信息(用户名、密码、类名等),Hibernate会关闭数据源,因为它将由Hibernate管理。

稍微了解一下历史,在早期,数据源会由J2EE容器(例如Tomcat)创建,然后在容器内的许多应用程序之间共享。属性hibernate.connection.datasource将是指向数据源的JNDI位置。

英文:

It's because you are providing an instance of a datasource. If you initialise a DS, there's a big chance you'll use it in other parts of your code, so closing the datasource would introduce an unexpected behaviour. This is actually a good practice, that the "module" that creates a resource is also responsible for disposing of it.

Hibernate will close the datasource if you provide the details of it (username, password, class name, etc), as it will be managed by Hibernate.

For a bit of history, in the old days, a DS would be created in by a J2EE container (e.g. Tomcat) and then shared across many apps inside that container. And the property hibernate.connection.datasource would be a JNDI location pointing to the datasource.

huangapple
  • 本文由 发表于 2020年8月12日 17:16:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/63373475.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定