【问题标题】:Hibernate prepareConnection/preparedStatement issuesHibernate prepareConnection/preparedStatement 问题
【发布时间】:2018-02-19 05:31:13
【问题描述】:

在我们的项目中,我们将 Spring 更新为 4.3.14.RELEASE,将 Hibernate 更新为 4.3.11.Final,因为我们开始看到两个警告:

  1. 警告 JDBC 连接重置与最初准备的连接不同 - 请确保使用连接释放模式 ON_CLOSE(默认)并针对 Hibernate 4.2+ 运行(或将 HibernateJpaDialect 的 prepareConnection 标志切换为 false

    • 解决方法是将释放模式切换到ON_CLOSE,这是我们不想要的——当我们的应用程序负载过重时,它会停止释放连接并且应用程序会卡住。这适用于发布模式 AFTER_TRANSACTION。
    • 该消息没有说明如果忽略此错误会发生什么。谷歌搜索没有显示任何明确的内容
    • 如果我们将prepareConnection 标志切换为false,会发生什么?我试图在 Hibernate 配置中找到这样的标志,但找不到。
  2. GooGooStatementCache:441 - 将准备好的语句相乘!

    • 此警告与前一个警告有关吗?这是我们应该担心的事情吗?

编辑:我将 Hibernate 更新为 5.2.13.Final

【问题讨论】:

    标签: java hibernate jpa c3p0


    【解决方案1】:

    通过以下设置禁用org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor

    spring:
      jpa:
        open-in-view: false
        hibernate:
          connection:
            release_mode: on_close # default mode, you can remove this line
    

    【讨论】:

    • 我认为 spring.jpa.open-in-view 配置选项是 Spring Boot 特定的。
    【解决方案2】:

    您可以尝试使用 hibernate.connection.handling_mode 属性

    hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_HOLD
    

    如果你正在使用 JTA

    hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION
    

    hibernate.connection.handling_mode=DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT
    

    查看此springframework javadoc 部分setPrepareConnection

    【讨论】:

      【解决方案3】:

      我在使用 Tomcat JDBC 池时遇到了同样的问题。

      问题出现在春季,因为他们在第 351 行进行了相等性检查 HibernateJpaDialect

      比较是在连接池(在您的情况下为 Tomcat 池或 c3p0)代理的连接上完成的。

      如果您设置 ON_CLOSE(休眠中的传统行为),则连接仅在会话重置/关闭时关闭,这不会引发任何问题,但可能会改变性能,尤其是在客户端保持休眠会话打开一段时间的情况下。

      如果您设置(默认)AFTER_TRANSACTION,则在事务完成后和会话关闭之前释放连接。 301行JdbcCoordinatorImpl

      通常,此方法 resetSessionState() 检查是否关闭连接两次 line 349if (this.preparedCon != null && this.session.isConnected())

      问题的出现是因为连接(由连接池代理)在第一次发布(事务之后)期间发生了变化,并且不满足相等性导致警告消息的原因。 此警告消息是误报

      【讨论】:

      • 这完美地解释了我们所经历的行为。在加载时,hikari 会保持连接活跃很长时间,直到我们用完可用的连接。这会引发“JDBCConnectionException:无法获取 JDBC 连接”。为了解决这个问题,我们切换到 AFTER_TRANSACTION,这似乎解决了第一个问题,但也引发了“JDBC Connection to reset ...”警告。现在我们禁止来自 HibernateJpaDialect 类的日志,但是有官方修复它吗?
      【解决方案4】:

      这里是multipleprepared statements的解释(来自GooGooStatementCache source):

      此连接已经准备了相同的语句, 并且那个其他实例还没有关闭,所以语句池 必须准备第二个 PreparedStatement 对象而不是重用 先前缓存的语句。新的 Statement 将被缓存,以防万一 您经常需要多份本声明。

      在英语中,这意味着相同的PreparedStatement 在签入相同的PreparedStatement 之前从Connection 签出。这是不寻常的。只有一个客户端和Thread 通常一次与Connection 交互,如果需要多次,通常会重用相同的PreparedStatement(重置其参数)。发生这种情况的最可能原因可能是因为应用程序没有 close() 和它打开的 PreparedStatements,依赖 c3p0 在 Connection 签入时清理它们。

      无论如何,这不是正确性问题,c3p0 会处理得很好。但它可能反映了可以稍微清理的代码(在使用后立即通过close()-ingPreparedStatements 或重用它们)以更有效地使用内存和资源。如果您使用的是当前版本(0.9.5.2),c3p0 应该会向您显示有问题的 PreparedStatement 的文本。


      我不知道您为什么会看到 Spring/Hibernate 警告。签出的 c3p0 Connections 是代理,但它们的身份在其客户端可见的生命周期内不会改变。稍微看一下source,在获取与Session 关联的Connection 时会出现一些反射和间接,然后将其与已检出的进行比较。也许某些东西会导致Session 刷新其关联的Connection,即使ConnectionSession 正在使用中?我希望我能提供更多帮助,但我不确定发生了什么。

      【讨论】:

      • 感谢您详尽的回复。由于我只是使用@Transactional 注释,我并没有真正打开,也没有关闭连接,所以很难说,它怎么会导致这些。我可以看到 PreparedStatement 的文本,但由于这是用于获取实体的 SQL,因此可以在项目中的任何位置。我想堆栈跟踪会更有帮助。无论如何,您只是在回答问题的第二部分,但第一部分是更重要的部分。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-28
      • 2013-06-12
      • 2011-04-19
      • 2016-04-15
      • 2013-07-19
      • 2011-01-31
      相关资源
      最近更新 更多