为什么Spring / Hibernate只读数据库事务运行得比读写慢?
好的,这是一个有趣的旅程。很多让我学习和分享。以下某些内容应该很明显,但希望我的无知以及我所学到的知识将对其他人有所帮助。
@Transaction(readonly = true)
通过一个setsession.transaction.read.only
同步JDBC调用开始一个会话,然后以一个setsession.transaction.read.write
调用结束。在进行读写呼叫时不会发送这些呼叫,这就是只读呼叫较慢的原因。
对问题2的更长答案涉及以下为提高远程数据库性能而采取的步骤的详细信息:
我们要做的第一件事是在阅读此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在仔细查看tcpdump输出(
tcpdump ... -X
为了获胜)时,我注意到进行了许多不必要的自动提交和只读/读写JDBC调用。升级到我们使用的令人敬畏的HikariCP连接池库的新版本可以帮助解决这一问题。在2.4.1版中,他们增加了一些智能,从而减少了其中的一些调用。只读事务开销低至120ms。仍以100ms读写。真好HikariCP的作者Brett Wooldridge向我指出了可能会有所帮助的MySQL驱动程序设置。非常感谢老兄。在我们的MySQL JDBC URL中添加以下设置,可以告诉驱动程序使用连接的软件状态,而不向服务器询问状态。
jdbc:mysql://.../database?useLocalSessionState=true&useLocalTransactionState=true
这些设置导致删除了更多同步JDBC命令。只读事务开销已降至60ms,现在与读写相同。呜呜
编辑/警告:
useLocalTransactionState=true发现驱动程序未发送事务信息的错误后,我们实际上回滚了添加操作。
- 但是在更多地看tcpdump输出时,我仍然看到正在发送只读/读写事务设置。我的最后一个解决方法是编写一个自定义的只读检测池,如果它看到对连接的第一个调用是,则会从一个特殊池发出连接
connection.setReadonly(true)
。
使用此自定义池可将只读和读写连接的事务开销降低到20ms。我认为它基本上消除了最后的JDBC事务开销调用。这是我从主页编写的两个类的源代码。该代码相对来说比较脆弱,并且依靠Hibernate来做
connection.setReadonly(true)第一件事,但是它似乎运行良好,我在XML和代码中仔细地记录了下来。
因此
@Transaction,经过几天的工作,基本开销从480ms变为了20ms。对一个
dao.find(...)方法的100个“现实生活”hibernate调用始于55秒,结束于4.5秒。漂亮的屁股。希望总是很容易将速度提高10倍。
希望我的经验能对其他人有所帮助。



