当前位置: 首页 > 面试题库 >

为什么Spring / Hibernate只读数据库事务运行得比读写慢?

吴哲
2023-03-14
问题内容

我一直在研究只读数据库和读写数据库事务的性能。MySQL服务器通过缓慢的VPN链接处于远程状态,因此我很容易看到事务类型之间的差异。这是与连接池有关的,我知道它是基于比较第一个和第二个JDBC调用而工作的。

当我将Spring AOP配置为在我的DAO调用上使用只读事务时,与读写相比,调用的 速度要慢 30-40%:

<!-- slower -->
<tx:method name="find*" read-only="true" propagation="REQUIRED" />
...
// slower
@Transaction(readOnly = true)

与:

<!-- faster -->
<tx:method name="find*" read-only="false" propagation="REQUIRED" />
...
// faster
@Transaction

看一下tcpdump,似乎只读事务正在与MySQL进行来回通信。这是只读转储与读写。

  1. 任何人都可以解释为什么只读呼叫需要更长的时间。这是预期的吗?

  2. 除了改善网络之外,我在做任何错事还是可以做些什么来提高他们的速度?刚刚发现这篇很棒的帖子,并提供了一些不错的性能建议。还有其他意见吗?

非常感谢。


问题答案:

为什么Spring / Hibernate只读数据库事务运行得比读写慢?

好的,这是一个有趣的旅程。很多让我学习和分享。以下某些内容应该很明显,但希望我的无知以及我所学到的知识将对其他人有所帮助。

对问题1的简短回答是,hibernate @Transaction(readOnly = true)通过一个 set session.transaction.read.only同步JDBC调用开始一个会话,然后以一个 set session.transaction.read.write调用结束。在进行读写呼叫时不会发送这些呼叫,这就是只读呼叫较慢的原因。

对问题2的更长答案涉及以下为提高远程数据库性能而采取的步骤的详细信息:

  1. 我们要做的第一件事是在阅读此OpenVPN优化页面之后将数据库VPN从TCP切换到UDP 。叹。我应该知道这一点。我还将以下设置添加到OpenVPN客户端和服务器配置中。只读事务开销从480ms减少到141ms,但仍比读写的100ms多。大赢

    ; Got these from: https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux
    

    proto udp
    tun-mtu 6000
    fragment 0
    mssfix 0


  2. 在仔细查看tcpdump输出(tcpdump ... -X为了获胜)时,我注意到进行了许多不必要的自动提交和只读/读写JDBC调用。升级到我们使用的令人敬畏的HikariCP连接池库的新版本可以帮助解决这一问题。在2.4.1版中,他们增加了一些智能,从而减少了其中的一些调用。只读事务开销低至120ms。仍以100ms读写。真好

  3. HikariCP的作者Brett Wooldridge向我指出了可能会有所帮助的MySQL驱动程序设置。非常感谢老兄。在我们的MySQL JDBC URL中添加以下设置,可以告诉驱动程序使用连接的软件状态,而不向服务器询问状态。

    jdbc:mysql://.../database?useLocalSessionState=true&useLocalTransactionState=true
    

这些设置导致删除了更多同步JDBC命令。只读事务开销已降至60ms,现在与读写相同。呜呜

编辑/警告:useLocalTransactionState=true发现驱动程序未发送事务信息的错误后,我们实际上回滚了添加操作。

  1. 但是在更多地看tcpdump输出时,我仍然看到正在发送只读/读写事务设置。我的最后一个解决方法是编写一个自定义的只读检测池,如果它看到对连接的第一个调用是,则会从一个特殊池发出连接connection.setReadOnly(true)

使用此自定义池可将只读和读写连接的事务开销降低到20ms。我认为它基本上消除了最后的JDBC事务开销调用。这是我从主页编写的两个类的源代码。该代码相对来说比较脆弱,并且依靠Hibernate来做connection.setReadOnly(true)第一件事,但是它似乎运行良好,我在XML和代码中仔细地记录了下来。

因此@Transaction,经过几天的工作,基本开销从480ms变为了20ms。对一个dao.find(...)方法的100个“现实生活”hibernate调用始于55秒,结束于4.5秒。漂亮的屁股。希望总是很容易将速度提高10倍。

希望我的经验能对其他人有所帮助。



 类似资料:
  • 问题内容: 为什么在Hibernate中需要事务才能进行只读操作? 以下事务是否在数据库中设置了锁定? 从数据库获取示例代码: 我可以 代替使用吗? 问题答案: 您实际上可能有理由将事务标记为只读。 阅读交易看起来确实很奇怪,在这种情况下,人们通常不会标记交易方法。但是JDBC仍然会创建事务,只是如果未显式设置其他选项,它将可以正常工作。 但是,不能保证您的方法不会写入数据库。如果将method标

  • 为什么我需要在Hibernate中使用事务进行只读操作? 以下事务是否在数据库中设置了锁? 从数据库获取的示例代码: 我可以使用会话吗。close()而不是tx.commit()?

  • 问题内容: 为什么在Hibernate中需要事务处理才能进行只读操作? 以下事务是否在数据库中设置了锁定? 从数据库获取示例代码: 我可以 代替使用吗? 问题答案: 你实际上可能有理由将事务标记为只读。 阅读交易看起来确实很奇怪,在这种情况下,人们通常不会标记交易方法。但是JDBC仍然会创建事务,只是如果未明确设置其他选项,它将可以正常工作。 但是,不能保证你的方法不会写入数据库。如果将metho

  • 问题内容: 只需要您对Spring声明式事务管理的专家意见。这是我的设置: DAO层是使用Spring JdbcTemplate的普通JDBC(没有Hibernate等) 服务层是具有声明式事务的POJO,如下所示- 通过上述设置,一切正常。但是,当我说时,我在日志文件中看到错误消息。对于服务层中的所有get *方法,都会发生这种情况。 现在我的问题是: 答:我必须设置为只读吗?我所有的方法都是纯

  • 问题内容: Hibernate 文档显示了以下示例: 即使仅打印了事件列表,为什么仍需要执行? 问题答案: SELECT还需要事务。没有任何事务就无法执行SELECT。使用某些SQL GUI工具从数据库中选择数据时,不必显式启动和结束事务,这是因为这些工具正在使用自动提交模式。在自动提交模式下,数据库将为每个SQL语句自动启动并提交事务,这样您就不必显式声明事务边界。 如果您不结束(即提交或回滚)

  • 问题内容: 我想比较使用Python和从读取的字符串输入的行数,并且震惊地看到我的C ++代码比等效的Python代码慢一个数量级。由于我的生锈,并且我还不是专家,所以请告诉我我做错了什么还是误解了什么。 (TLDR答案:包括以下声明:或仅使用fgets代替。 TLDR结果:一直滚动到我的问题的底部,然后查看表格。) C ++代码: 等同于Python: 这是我的结果: 我应该注意,我在Mac O