親愛的大家,
我敢肯定,你們中的許多人都在使用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; doecho "SELECT 1 FROM DUAL;"
done | mysql
查看iostat(8)的輸出,結果表明機器上沒有I / O。 top(1)確實表明機器正在運行。 由此可見,這些SELECT語句不會引起磁盤I / O。
接下來,我添加了Hibernate的自動提交命令,如下所示。
while true; doecho "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