亲爱的大家,
我敢肯定,你们中的许多人都在使用Hibernate和MySQL,我自己在这里和那里都使用它。 通常,编程模型是不错的,但是普通的JDBC可以快很多已经不是什么秘密了。 在这篇文章中,我想引起您的注意Hibernate在您的MySQL服务器中引起的一个小问题。
如果跟踪Hibernate发送到MySQL数据库的SQL,就会发现一致地,Hibernate以“ SET autocommit = 0”开始每个事务,并以“ commit”结束,然后是“ SET autocommit = 1”。 这些语句看似无害,但它们使MySQL将某些内部状态刷新到磁盘上。 简而言之,每次Hibernate调用这两个语句之一时,MySQL都会编写通常不会编写的内容。 因此,与使用普通JDBC相比,使用Hibernate会使MySQL服务器在磁盘上的依赖更多。
我做了一个小实验来证明这一点。 要重复此实验,请找到带有MySQL数据库的空闲计算机。 机器不应运行任何会导致磁盘I / O的东西,否则效果将不像我看到的那么容易。
首先,我发送了一整串“ SELECT DUAL DUAL;” 命令进入MySQL提示。 像这样:
while true; do
echo "SELECT 1 FROM DUAL;"
done | mysql
查看iostat(8)的输出,结果表明机器上没有I / O。 top(1)确实表明机器正在运行。 由此可见,这些SELECT语句不会引起磁盘I / O。
接下来,我添加了Hibernate的自动提交命令,如下所示。
while true; do
echo "SET AUTOCOMMIT=0;"
echo "SELECT 1 FROM DUAL;"
echo "COMMIT;"
echo "SET AUTOCOMMIT=1;"
done | mysql
这次,iostat(8)确实表明存在磁盘I / O。 MySQL服务器比以前更努力地工作,同时仍然提供完全相同的答案。 这仅来自单个线程。 您的应用程序可能会在多个线程和连接上同时发出这些语句,从而加剧了问题。
对于无论如何都会导致I / O的查询,我认为这种开销可以忽略不计。 对于小型读取查询,这意味着您突然在数据库服务器上执行磁盘I / O。
我还没有找到一种方法来向Hibernate解释我不想让它将自动提交语句发送到数据库。 您可以在Hibernate中关闭自动提交功能,但是只能关闭Hibernate的内部自动提交功能。 它不会停止将这些命令发送到数据库。
读取Hibernate源代码(尤其是org.hibernate.transaction.JDBCTransaction的源代码)可以看到,休眠使它在每次事务之前强制自动提交连接失败,并在之后重置它。 这是硬编码的。 休眠*想要*自动提交为关闭。
如果我的MySQL服务器仅服务于启用了Hibernate的应用程序,我可能会考虑将数据库服务器的默认自动提交模式关闭。 另外,我可以使用elideSetAutoCommits标志,这可能会减少自动提交切换的数量。 但是,这严重破坏了POLA 。 另外,我的服务器不仅仅提供支持Hibernate的应用程序,因此更改默认设置肯定会破坏其他地方。
所以,这让我陷入困境。 我不能告诉Hibernate不要发出“ SET autocommit”,JDBC驱动程序不会禁止它们,也不能告诉MySQL忽略它们。
参考: Hibernate发送自动提交命令会强制MySQL在Java Monitor论坛上从我们的JCG合作伙伴 Kees Jan 做过多的磁盘I / O。
快乐编码
拜伦
相关文章:
- Hibernate映射集合性能问题
- DataNucleus 3.0与Hibernate 3.5
- 提升您的休眠引擎
- GWT 2 Spring 3 JPA 2 Hibernate 3.5教程
- JBoss 4.2.x Spring 3 JPA Hibernate教程
翻译自: https://www.javacodegeeks.com/2011/07/hibernate-autocommit-commands-force.html