文章出处:我的博客 我的生活
出处:http://blog.csdn.net/jxspace/archive/2006/09/18/1234002.aspx
9月17日在CSDN社区的Java技术栏中看到了网友lifejoy的一个贴子,题为“hibernate 写入性能暴差,如何配置?”,详细链接请见
http://community.csdn.net/Expert/TopicView3.asp?id=5025307
lifejoy网友写了段测试程序,用Hibernate作为持久手段测试了大数据量写入MySql数据库的性能。程序主要使用了一个循环嵌套,最里层循 环为批量插入记录的代码,每一批插1000条记录,最外层循环为批次的控制,一共循环100批次,这样总的数据写入量为1000x100共十万记录。从 lifejoy的测试数据看,用JDBC直接写的速率是600-800条/秒,而用Hibernate写的速率会从一开始的300多条降至几十条每秒,这 个差距非常之大,难怪lifejoy使用了“暴差”这一非常使人触目惊心的语言。
Hibernate的写入性能到底如何?真的到了“暴差”这样的地步么?其性能与JDBC直写相比,到底差距多大?这些个问题,通过google 结果,众说纷纭,莫衷一是,在台湾JavaWorld论坛上,有网友贴出了Hibernate比JDBC性能更加优越的测试结果分析图,也有很多网友在诟 病Hibernate在ORM的同时丧失了性能,到底真相在何方?由于今年做了一个基于Oracle的大型系统,需要支撑高并发数据访问量,在决定系统架 构的时候,首席架构师选择了iBatis,而放弃了Hibernate,其中一个最大的考虑就是这个性能因素,可惜当初没有进行技术实际论证,于是有了今 天的这个“考”,打算通过实际测试结果来验证一下Hibernate的性能情况,以澄清如下问题:
<!--[if !supportLists]-->1. <!--[endif]-->Hibernate ORM读写与JDBC方式读写在性能上孰优孰劣?
<!--[if !supportLists]-->2. <!--[endif]-->优势多少?劣势又是几何?
依照lifejoy的思路下写以下一段代码:
package com.gmail.newmanhuang.learnhibernate;
import java.util.Iterator;
import java.util.List;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.Criteria;
import org.hibernate.criterion.Expression;
import com.gmail.newmanhuang.learnhibernate.model.Person;
import java.sql.*;
public class LearnHibernateMain {
private Configuration config;
private SessionFactory sessionFactory;
private Session session;
public static void main(String[] args) {
LearnHibernateMain lh=new LearnHibernateMain();
//用hibernate创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入
//lh.createPersons(10, 1000, 100);
//用jdbc直接创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入
lh.createPersonsByJDBC(10, 1000,100);
}
//用hibernate创建person记录, loopNum为循环插入的次数,batchNum1为每次循环插入的记录数,batchNum2为物理批量插入记录数
private void createPersons(int loopNum,int batchNum1,int batchNum2){
setup();
System.out.println("hibernate record creating testing./r/n"
+ "loop times:" + loopNum + "/r/nbatch number:" + batchNum1);
for(int i=0;i<loopNum;i++){
try {
Thread.sleep(50);//休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
long fPoint=System.currentTimeMillis();
Transaction tx = session.beginTransaction();
for(int j=0;j<batchNum1;j++){
Person person = new Person();
person.setName("name-" + i +"-"+ j);
person.setAge(new Integer(25));
session.save(person);
//batch flush
if ( j % batchNum2 == 0 ) {//执行物理批量插入
session.flush();
session.clear();
}
}
tx.commit();
long tPoint=System.currentTimeMillis();
//打印插入batchNum1条记录的速率(条/秒)
System.out.println(
"the " + i + " batch" + "(" + batchNum1 +") rcds/s:"
+ ((double)batchNum1/(tPoint-fPoint))*1000);
}
teardown();
}
//用jdbc创建person记录, loopNum为循环插入的次数,batchNum1为每次循环插入的记录数,batchNum2为物理批量插入记录数
private void createPersonsByJDBC(int loopNum,int batchNum1,int batchNum2){
System.out.println("JDBC record creating testing./r/n"
+ "loop times:" + loopNum + "/r/nbatch number:" + batchNum1);
Connection conn=getDBConn();
try{
PreparedStatement pstmt=conn.prepareStatement("insert into person(name,age) values(?,?)");
for(int i=0;i<loopNum;i++){
try {
Thread.sleep(50);//休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
long fPoint=System.currentTimeMillis();
conn.setAutoCommit(false);
for(int j=0;j<batchNum1;j++){
String name="name-" + i +"-"+ j;
pstmt.setString(1, name);
pstmt.setInt(2, 25);
pstmt.addBatch();
if(j%batchNum2==0){//执行物理批量插入
pstmt.executeBatch();
conn.commit();
}
}
pstmt.executeBatch();
conn.commit();
conn.setAutoCommit(true);
long tPoint=System.currentTimeMillis();
//打印插入batchNum1条记录的速率(条/秒)
System.out.println(
"the " + i + " batch" + "(" + batchNum1 +") rcds/s:"
+ ((double)batchNum1/(tPoint-fPoint))*1000);
}
pstmt.close();
}catch(Exception x){
try{
conn.close();
}catch(Exception x1){
}
}
}
//获取JDBC连接
private Connection getDBConn(){
Connection conn=null;
try {
Class.forName("org.gjt.mm.mysql.Driver");
conn=DriverManager.getConnection("jdbc:mysql://localhost/learnhibernate", "root", "");
} catch (Exception x) {
}
return conn;
}
//初始化hibernate数据库环境
private void setup(){
config = new Configuration().configure();
sessionFactory = config.buildSessionFactory();
session = sessionFactory.openSession();
}
//销毁hibernate数据库环境
private void teardown(){
session.close();
sessionFactory.close();
}
}
测试环境主要为:J2SDK1.4.2_04, MySql4.1.9-Max, Hibernate3.1, IBM Thinkpad R32-P4 1.8G, 512M Memory;MySql中待插表的类型为INNODB,以支持事务,ISAM类型表的读写速率要远高于INNODB,这里不采用ISAM是因为不支持事 务。
主要分为三个测试场景,以下为三个场景的测试记录和分析:
测试场景一:
############# 测试环境一 #######################
mysql版本:4.1.9-max
jdbc驱动:mysql-connector-java-3.1.11-bin.jar
hibernate: 3.1
################################################
1.hibernate批量插入,创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入操作
测试记录:
======================================================================
hibernate record creating testing.
loop times:10
batch number:1000
the 0 batch(1000) rcds/s:172.1763085399449
the 1 batch(1000) rcds/s:214.73051320592657
the 2 batch(1000) rcds/s:302.6634382566586
the 3 batch(1000) rcds/s:321.13037893384717
the 4 batch(1000) rcds/s:318.9792663476874
the 5 batch(1000) rcds/s:316.05562579013906
the 6 batch(1000) rcds/s:318.9792663476874
the 7 batch(1000) rcds/s:317.05770450221945
the 8 batch(1000) rcds/s:317.9650238473768
the 9 batch(1000) rcds/s:314.96062992125985
测试结果:
hibernate新记录创建平均速率:~290条/秒
======================================================================
2.jdbc批量插入,创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入操作
测试记录:
======================================================================
JDBC record creating testing.
loop times:10
batch number:1000
the 0 batch(1000) rcds/s:812.3476848090983
the 1 batch(1000) rcds/s:988.1422924901185
the 2 batch(1000) rcds/s:1233.0456226880394
the 3 batch(1000) rcds/s:1314.060446780552
the 4 batch(1000) rcds/s:1201.923076923077
the 5 batch(1000) rcds/s:1349.527665317139
the 6 batch(1000) rcds/s:853.9709649871904
the 7 batch(1000) rcds/s:1218.026796589525
the 8 batch(1000) rcds/s:1175.0881316098707
the 9 batch(1000) rcds/s:1331.5579227696405
测试结果:
jdbc新记录创建平均速率:~1147条/秒
======================================================================
******测试环境一结论:jdbc性能明显优于hibernate,写入速率比jdbc/hibernate=3.95
测试场景二:
############# 测试环境二 #######################
mysql版本:4.1.9-max
jdbc驱动:mysql-connector-java-3.0.11-bin.jar(注意这里更换了mysql的connectorJ驱动!!!)
hibernate: 3.1
################################################
1.hibernate批量插入,创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入操作
测试记录:
======================================================================hibernate record creating testing.
loop times:10
batch number:1000
the 0 batch(1000) rcds/s:536.7686527106817
the 1 batch(1000) rcds/s:504.28643469490675
the 2 batch(1000) rcds/s:1062.6992561105205
the 3 batch(1000) rcds/s:1122.334455667789
the 4 batch(1000) rcds/s:1133.7868480725624
the 5 batch(1000) rcds/s:1122.334455667789
the 6 batch(1000) rcds/s:1008.0645161290322
the 7 batch(1000) rcds/s:1085.7763300760043
the 8 batch(1000) rcds/s:1074.1138560687434
the 9 batch(1000) rcds/s:1096.4912280701756
测试结果:
新记录创建平均速率:~974条/秒
======================================================================
2.jdbc批量插入,创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入操作
测试记录:
======================================================================
JDBC record creating testing.
loop times:10
batch number:1000
the 0 batch(1000) rcds/s:1231.527093596059
the 1 batch(1000) rcds/s:1406.4697609001407
the 2 batch(1000) rcds/s:2000.0
the 3 batch(1000) rcds/s:1692.047377326565
the 4 batch(1000) rcds/s:1386.9625520110958
the 5 batch(1000) rcds/s:1349.527665317139
the 6 batch(1000) rcds/s:1074.1138560687434
the 7 batch(1000) rcds/s:1386.9625520110958
the 8 batch(1000) rcds/s:1636.6612111292961
the 9 batch(1000) rcds/s:1814.8820326678765
测试结果:
新记录创建平均速率:~1497条/秒
======================================================================
******测试环境二结论:jdbc性能仍优于hibernate,写入速率比jdbc/hibernate =1.58
测试场景三:
############# 测试环境三 #######################
mysql版本:4.1.9-max
jdbc驱动:mysql-connector-java-3.0.11-bin.jar(与测试环境二使用同样的驱动)
hibernate: 3.1
特别说明:记录插入不使用事务
################################################
1.jdbc批量插入,创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入操作,不使用事务(注意这里,不使用事务!!)
测试记录:
===========================================================================================
JDBC record creating testing.
loop times:10
batch number:1000
the 0 batch(1000) rcds/s:43.11645755184754
the 1 batch(1000) rcds/s:34.32651379925854
the 2 batch(1000) rcds/s:40.65701740120345
the 3 batch(1000) rcds/s:62.44925997626928
the 4 batch(1000) rcds/s:69.58942240779402
the 5 batch(1000) rcds/s:42.45743641998896
the 6 batch(1000) rcds/s:44.420753375977256
the 7 batch(1000) rcds/s:44.44049417829527
the 8 batch(1000) rcds/s:56.63797009515179
the 9 batch(1000) rcds/s:71.73601147776183
测试结果:
新记录创建平均速率:~50条/秒
======================================================================
测试结果分析:
1. 在同等测试环境和条件下,hibernate优于jdbc这种说法是错误的,从测试结果来看, jdbc要优于hibernate,这从理论上是可以理解的,hibernate的基础就是jdbc,它不可能优于jdbc。
2. 影响数据库操作性能的因素很多,主要包括:
1)数据库自身
如mysql表类型,是ISAM还是innodb
2)数据库驱动
从测试数据和结果看,mysql的3.0.11版本的驱动显然更适合于mysql4.1.9版本的数据库,而高版本的3.1.11用于 hibernate的插入操作则会丧失近3.5倍的执行效率,另外,经过笔者测试,在3.1.11版本的驱动中,使用与不使用批次(batch)插入操作 居然没有任何区别,这也能解释一些技术论坛上提到的hibernate批处理操作有时候会实效这个令人困惑的问题。
3)操作数据库的程序本身
测试环境3表明,当mysql的表类型为innodb时,即使是采用JDBC直接写的方式,不采用事务方式插入记录,写入速率几乎是“蜗速”(~50条/秒),这可以说是“杀手级”的因素了。
结论:
<!--[if !supportLists]-->1. 笔者估计在大数据量写入状况下,Hibernate的性能损失在30%-35%左右<!--[endif]-->
<!--[if !supportLists]-->2. 对于要获取高性能数据读写的系统,不推荐使用Hibernate的ORM方式进行数据读写。<!--[endif]-->
<!--[if !supportLists]-->3. 性能的优劣除了所采用的技术决定外,更取决于使用技术的人,比如在测试环境三中,不采用事务方式写数据,其速度简直不能以“暴差”来形容,想想这样一种情 况,让你去开一辆法拉利F1赛车,你一定能想象得到你驾驶的速度。:)<!--[endif]-->
后记:
在进行测试的时候,起初笔者使用的JDBC驱动是J/Conncector 3.1.11版本,发现Hibernate的批量写设置根本不起作用,是否使用批量写根本就没有差别,在一些网站上面也发现有类似的疑问,经过更换为 3.0.x版本驱动后,批量写才生效,而且无论是Hibernate方式还是JDBC方式下,写记录的性能明显提升,表明3.0.X的驱动更适合于 MySql4.1,为什么高版本的3.1.11反而在低版本数据库上面表现出低效?笔者在安装Roller这个Apache孵化器blog项目的时候,也 对安装指导中推荐使用3.0.X版本来匹配MySql4.1数据库这个问题比较疑惑,可惜Roller的InstallGuid没有做具体解释,感兴趣的 网友可以到Roller网站的wiki上去弄清楚这个问题,并把答案做个回复,非常感谢。这个插曲还说明了一个道理——“升级并非总是好事”。
出处:http://blog.csdn.net/jxspace/archive/2006/09/18/1234002.aspx
9月17日在CSDN社区的Java技术栏中看到了网友lifejoy的一个贴子,题为“hibernate 写入性能暴差,如何配置?”,详细链接请见
http://community.csdn.net/Expert/TopicView3.asp?id=5025307
lifejoy网友写了段测试程序,用Hibernate作为持久手段测试了大数据量写入MySql数据库的性能。程序主要使用了一个循环嵌套,最里层循 环为批量插入记录的代码,每一批插1000条记录,最外层循环为批次的控制,一共循环100批次,这样总的数据写入量为1000x100共十万记录。从 lifejoy的测试数据看,用JDBC直接写的速率是600-800条/秒,而用Hibernate写的速率会从一开始的300多条降至几十条每秒,这 个差距非常之大,难怪lifejoy使用了“暴差”这一非常使人触目惊心的语言。
Hibernate的写入性能到底如何?真的到了“暴差”这样的地步么?其性能与JDBC直写相比,到底差距多大?这些个问题,通过google 结果,众说纷纭,莫衷一是,在台湾JavaWorld论坛上,有网友贴出了Hibernate比JDBC性能更加优越的测试结果分析图,也有很多网友在诟 病Hibernate在ORM的同时丧失了性能,到底真相在何方?由于今年做了一个基于Oracle的大型系统,需要支撑高并发数据访问量,在决定系统架 构的时候,首席架构师选择了iBatis,而放弃了Hibernate,其中一个最大的考虑就是这个性能因素,可惜当初没有进行技术实际论证,于是有了今 天的这个“考”,打算通过实际测试结果来验证一下Hibernate的性能情况,以澄清如下问题:
<!--[if !supportLists]-->1. <!--[endif]-->Hibernate ORM读写与JDBC方式读写在性能上孰优孰劣?
<!--[if !supportLists]-->2. <!--[endif]-->优势多少?劣势又是几何?
依照lifejoy的思路下写以下一段代码:
package com.gmail.newmanhuang.learnhibernate;
import java.util.Iterator;
import java.util.List;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.Criteria;
import org.hibernate.criterion.Expression;
import com.gmail.newmanhuang.learnhibernate.model.Person;
import java.sql.*;
public class LearnHibernateMain {
private Configuration config;
private SessionFactory sessionFactory;
private Session session;
public static void main(String[] args) {
LearnHibernateMain lh=new LearnHibernateMain();
//用hibernate创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入
//lh.createPersons(10, 1000, 100);
//用jdbc直接创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入
lh.createPersonsByJDBC(10, 1000,100);
}
//用hibernate创建person记录, loopNum为循环插入的次数,batchNum1为每次循环插入的记录数,batchNum2为物理批量插入记录数
private void createPersons(int loopNum,int batchNum1,int batchNum2){
setup();
System.out.println("hibernate record creating testing./r/n"
+ "loop times:" + loopNum + "/r/nbatch number:" + batchNum1);
for(int i=0;i<loopNum;i++){
try {
Thread.sleep(50);//休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
long fPoint=System.currentTimeMillis();
Transaction tx = session.beginTransaction();
for(int j=0;j<batchNum1;j++){
Person person = new Person();
person.setName("name-" + i +"-"+ j);
person.setAge(new Integer(25));
session.save(person);
//batch flush
if ( j % batchNum2 == 0 ) {//执行物理批量插入
session.flush();
session.clear();
}
}
tx.commit();
long tPoint=System.currentTimeMillis();
//打印插入batchNum1条记录的速率(条/秒)
System.out.println(
"the " + i + " batch" + "(" + batchNum1 +") rcds/s:"
+ ((double)batchNum1/(tPoint-fPoint))*1000);
}
teardown();
}
//用jdbc创建person记录, loopNum为循环插入的次数,batchNum1为每次循环插入的记录数,batchNum2为物理批量插入记录数
private void createPersonsByJDBC(int loopNum,int batchNum1,int batchNum2){
System.out.println("JDBC record creating testing./r/n"
+ "loop times:" + loopNum + "/r/nbatch number:" + batchNum1);
Connection conn=getDBConn();
try{
PreparedStatement pstmt=conn.prepareStatement("insert into person(name,age) values(?,?)");
for(int i=0;i<loopNum;i++){
try {
Thread.sleep(50);//休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
long fPoint=System.currentTimeMillis();
conn.setAutoCommit(false);
for(int j=0;j<batchNum1;j++){
String name="name-" + i +"-"+ j;
pstmt.setString(1, name);
pstmt.setInt(2, 25);
pstmt.addBatch();
if(j%batchNum2==0){//执行物理批量插入
pstmt.executeBatch();
conn.commit();
}
}
pstmt.executeBatch();
conn.commit();
conn.setAutoCommit(true);
long tPoint=System.currentTimeMillis();
//打印插入batchNum1条记录的速率(条/秒)
System.out.println(
"the " + i + " batch" + "(" + batchNum1 +") rcds/s:"
+ ((double)batchNum1/(tPoint-fPoint))*1000);
}
pstmt.close();
}catch(Exception x){
try{
conn.close();
}catch(Exception x1){
}
}
}
//获取JDBC连接
private Connection getDBConn(){
Connection conn=null;
try {
Class.forName("org.gjt.mm.mysql.Driver");
conn=DriverManager.getConnection("jdbc:mysql://localhost/learnhibernate", "root", "");
} catch (Exception x) {
}
return conn;
}
//初始化hibernate数据库环境
private void setup(){
config = new Configuration().configure();
sessionFactory = config.buildSessionFactory();
session = sessionFactory.openSession();
}
//销毁hibernate数据库环境
private void teardown(){
session.close();
sessionFactory.close();
}
}
测试环境主要为:J2SDK1.4.2_04, MySql4.1.9-Max, Hibernate3.1, IBM Thinkpad R32-P4 1.8G, 512M Memory;MySql中待插表的类型为INNODB,以支持事务,ISAM类型表的读写速率要远高于INNODB,这里不采用ISAM是因为不支持事 务。
主要分为三个测试场景,以下为三个场景的测试记录和分析:
测试场景一:
############# 测试环境一 #######################
mysql版本:4.1.9-max
jdbc驱动:mysql-connector-java-3.1.11-bin.jar
hibernate: 3.1
################################################
1.hibernate批量插入,创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入操作
测试记录:
======================================================================
hibernate record creating testing.
loop times:10
batch number:1000
the 0 batch(1000) rcds/s:172.1763085399449
the 1 batch(1000) rcds/s:214.73051320592657
the 2 batch(1000) rcds/s:302.6634382566586
the 3 batch(1000) rcds/s:321.13037893384717
the 4 batch(1000) rcds/s:318.9792663476874
the 5 batch(1000) rcds/s:316.05562579013906
the 6 batch(1000) rcds/s:318.9792663476874
the 7 batch(1000) rcds/s:317.05770450221945
the 8 batch(1000) rcds/s:317.9650238473768
the 9 batch(1000) rcds/s:314.96062992125985
测试结果:
hibernate新记录创建平均速率:~290条/秒
======================================================================
2.jdbc批量插入,创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入操作
测试记录:
======================================================================
JDBC record creating testing.
loop times:10
batch number:1000
the 0 batch(1000) rcds/s:812.3476848090983
the 1 batch(1000) rcds/s:988.1422924901185
the 2 batch(1000) rcds/s:1233.0456226880394
the 3 batch(1000) rcds/s:1314.060446780552
the 4 batch(1000) rcds/s:1201.923076923077
the 5 batch(1000) rcds/s:1349.527665317139
the 6 batch(1000) rcds/s:853.9709649871904
the 7 batch(1000) rcds/s:1218.026796589525
the 8 batch(1000) rcds/s:1175.0881316098707
the 9 batch(1000) rcds/s:1331.5579227696405
测试结果:
jdbc新记录创建平均速率:~1147条/秒
======================================================================
******测试环境一结论:jdbc性能明显优于hibernate,写入速率比jdbc/hibernate=3.95
测试场景二:
############# 测试环境二 #######################
mysql版本:4.1.9-max
jdbc驱动:mysql-connector-java-3.0.11-bin.jar(注意这里更换了mysql的connectorJ驱动!!!)
hibernate: 3.1
################################################
1.hibernate批量插入,创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入操作
测试记录:
======================================================================hibernate record creating testing.
loop times:10
batch number:1000
the 0 batch(1000) rcds/s:536.7686527106817
the 1 batch(1000) rcds/s:504.28643469490675
the 2 batch(1000) rcds/s:1062.6992561105205
the 3 batch(1000) rcds/s:1122.334455667789
the 4 batch(1000) rcds/s:1133.7868480725624
the 5 batch(1000) rcds/s:1122.334455667789
the 6 batch(1000) rcds/s:1008.0645161290322
the 7 batch(1000) rcds/s:1085.7763300760043
the 8 batch(1000) rcds/s:1074.1138560687434
the 9 batch(1000) rcds/s:1096.4912280701756
测试结果:
新记录创建平均速率:~974条/秒
======================================================================
2.jdbc批量插入,创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入操作
测试记录:
======================================================================
JDBC record creating testing.
loop times:10
batch number:1000
the 0 batch(1000) rcds/s:1231.527093596059
the 1 batch(1000) rcds/s:1406.4697609001407
the 2 batch(1000) rcds/s:2000.0
the 3 batch(1000) rcds/s:1692.047377326565
the 4 batch(1000) rcds/s:1386.9625520110958
the 5 batch(1000) rcds/s:1349.527665317139
the 6 batch(1000) rcds/s:1074.1138560687434
the 7 batch(1000) rcds/s:1386.9625520110958
the 8 batch(1000) rcds/s:1636.6612111292961
the 9 batch(1000) rcds/s:1814.8820326678765
测试结果:
新记录创建平均速率:~1497条/秒
======================================================================
******测试环境二结论:jdbc性能仍优于hibernate,写入速率比jdbc/hibernate =1.58
测试场景三:
############# 测试环境三 #######################
mysql版本:4.1.9-max
jdbc驱动:mysql-connector-java-3.0.11-bin.jar(与测试环境二使用同样的驱动)
hibernate: 3.1
特别说明:记录插入不使用事务
################################################
1.jdbc批量插入,创建10000条记录,分10次插入,每次1000条,每100条记录做一次批量插入操作,不使用事务(注意这里,不使用事务!!)
测试记录:
===========================================================================================
JDBC record creating testing.
loop times:10
batch number:1000
the 0 batch(1000) rcds/s:43.11645755184754
the 1 batch(1000) rcds/s:34.32651379925854
the 2 batch(1000) rcds/s:40.65701740120345
the 3 batch(1000) rcds/s:62.44925997626928
the 4 batch(1000) rcds/s:69.58942240779402
the 5 batch(1000) rcds/s:42.45743641998896
the 6 batch(1000) rcds/s:44.420753375977256
the 7 batch(1000) rcds/s:44.44049417829527
the 8 batch(1000) rcds/s:56.63797009515179
the 9 batch(1000) rcds/s:71.73601147776183
测试结果:
新记录创建平均速率:~50条/秒
======================================================================
测试结果分析:
1. 在同等测试环境和条件下,hibernate优于jdbc这种说法是错误的,从测试结果来看, jdbc要优于hibernate,这从理论上是可以理解的,hibernate的基础就是jdbc,它不可能优于jdbc。
2. 影响数据库操作性能的因素很多,主要包括:
1)数据库自身
如mysql表类型,是ISAM还是innodb
2)数据库驱动
从测试数据和结果看,mysql的3.0.11版本的驱动显然更适合于mysql4.1.9版本的数据库,而高版本的3.1.11用于 hibernate的插入操作则会丧失近3.5倍的执行效率,另外,经过笔者测试,在3.1.11版本的驱动中,使用与不使用批次(batch)插入操作 居然没有任何区别,这也能解释一些技术论坛上提到的hibernate批处理操作有时候会实效这个令人困惑的问题。
3)操作数据库的程序本身
测试环境3表明,当mysql的表类型为innodb时,即使是采用JDBC直接写的方式,不采用事务方式插入记录,写入速率几乎是“蜗速”(~50条/秒),这可以说是“杀手级”的因素了。
结论:
<!--[if !supportLists]-->1. 笔者估计在大数据量写入状况下,Hibernate的性能损失在30%-35%左右<!--[endif]-->
<!--[if !supportLists]-->2. 对于要获取高性能数据读写的系统,不推荐使用Hibernate的ORM方式进行数据读写。<!--[endif]-->
<!--[if !supportLists]-->3. 性能的优劣除了所采用的技术决定外,更取决于使用技术的人,比如在测试环境三中,不采用事务方式写数据,其速度简直不能以“暴差”来形容,想想这样一种情 况,让你去开一辆法拉利F1赛车,你一定能想象得到你驾驶的速度。:)<!--[endif]-->
后记:
在进行测试的时候,起初笔者使用的JDBC驱动是J/Conncector 3.1.11版本,发现Hibernate的批量写设置根本不起作用,是否使用批量写根本就没有差别,在一些网站上面也发现有类似的疑问,经过更换为 3.0.x版本驱动后,批量写才生效,而且无论是Hibernate方式还是JDBC方式下,写记录的性能明显提升,表明3.0.X的驱动更适合于 MySql4.1,为什么高版本的3.1.11反而在低版本数据库上面表现出低效?笔者在安装Roller这个Apache孵化器blog项目的时候,也 对安装指导中推荐使用3.0.X版本来匹配MySql4.1数据库这个问题比较疑惑,可惜Roller的InstallGuid没有做具体解释,感兴趣的 网友可以到Roller网站的wiki上去弄清楚这个问题,并把答案做个回复,非常感谢。这个插曲还说明了一个道理——“升级并非总是好事”。