哪里是偷换概念?

帖子里的意思:因为大家没有“专业”的进行测试,所以不专业的测试是没有意义的。

不要搞人身攻击。

难怪也有人说“咆哮”。

uu_snow,已经学到很多的东西了,这就是意义吧。

如果他不作这个测试,如果他不把测试结果发到这里,他能这么快学到这些东西么?

大家做测试,不是要给出一个权威的结论,只是为了自己弄明白几个问题罢了。

>>我曾经在hibernate forum的一个贴子中看到Gavin说:即使是查询也要放在一个事务中,理由有
1事务读并不比非事务读慢
2不会读到脏数据(当然要你的隔离级别足够高),而非事务读则可能<<

是这样的,事务读比非事务读稍微慢一点,大概慢1ms左右,基本上可以认为没有差别,但是事务读对数据库造成的压力比非事务读要大很多,这一点是很明显的,很容易观察到。

在一个多用户的系统中,脏数据的定义是什么?即使你从数据库取出的时候是新鲜的数据,但是当你把数据显示输出的过程中,可能数据库中的数据已经被别的用户更新过了,那么仍然是脏数据。我认为除非是强调数据实时性的系统,否则没有必要过度强调脏数据的新鲜程度,这样做的后果是加重了数据库的负担。其实Hibernate的Transaction就是JDBC事务的commit,rollback,如果你直接写JDBC代码,你会考虑查询数据的sql语句也写上commit和rollback吗?

呵呵,在Hibernate的事务方面我确实不完全同意Gavin的看法。


My God, 又染上了一身腥!

robbin

上一页我已经把我的程序和环境都贴出来了,
你看到了没

只是不同意robbin的立场罢了。
over。
robbin慢慢给uu_snow 解答把。

想robbin这么热心人是jdon活跃的一个动力。

呵呵,每个人看法不一样,不必太在意!

测试我已经做完了,测试用例是我自己重新写的,结果已经有了。不过我仍然要事先声明的是,这个测试非常粗糙,而且只考察了执行时间,没有准确考察JVM的CPU和内存堆栈情况,因此不能说有任何参考价值。即便单看执行时间,也有很多没有考虑的因素,都有可能造成结果的偏离。

测试环境:
CPU: Duron700 (在测试过程中,某些项目已经造成瓶颈,因此会影响某些测试结果)
内存:PC133 SDRAM 512MB (JVM参数加上 -Xms256m -Xmx256m,避免由于内存不足造成测试项目失败)
硬盘: IBM GXP 2代 30GB 7200转
Windows2000 Professional sp4 简体中文版
数据库: MySQL4.0.13,创建的数据库表 Type=InnoDB
JDBC驱动: 使用MySQL官方驱动mysql-connector-java-3.0.8-stable-bin.jar

Hibernate关闭数据库连接池:hibernate.connection.pool_size 0
JDBC直接使用DriverManager连接数据库
不使用连接池是为了排除连接池性能差异造成的偏差。

不使用App Server,直接写Java程序测试,避免App Server造成偏差。

测试项目1:插入1000条记录到cat表

子项目1:使用循环变量i作为主键,插入id字段
Hibernate: 1.83s
JDBC Batch: 1.3s (JDBC使用批处理命令)

显然JDBC Batch方式快一些

子项目2:Hibernate使用uuid.hex生成主键,JDBC采用当前时间戳加循环变量构造主键
Hibernate: 1.9秒
JDBC Batch: 1.3秒

仍然是JDBC Batch方式快

测试项目2:读取所有数据

子项目1:cat表记录有3115条
Hibernate List:0.8秒
Hibernate Iterator: 5.5秒
JDBC : 0.33秒

JDBC速度最快,Hibernate List其次,Iterator最慢。

子项目2: cat表有30万1千条记录
Hibernate List:22.2秒
Hibernate Iterator: N/A
JDBC : 12.5秒

JDBC不但快,而且占用内存少,峰值内存75MB,Hibernate List其次,峰值内存占用140MB,Iterator方式下,观察到内存以每秒几十K的速度增加,估计不增加到140MB,是不会完成测试过程的,由于不耐烦等待,终止测试。


结论:
1、JDBC仍然是最快的访问方式,不论是Create还是Read操作,都是JDBC快。

2、Hibernate使用uuid.hex构造主键,性能稍微有点损失,但是不大。

3、Create操作,JDBC在使用批处理的方式下速度比Hibernate快,使用批处理方式耗用JVM内存比不使用批处理方式要多得多。

4、读取数据,Hibernate的Iterator速度非常缓慢,因为他是每次next的时候才去数据库取数据,这一点从观察任务管理器的java进程占用内存的变化也可以看得很清楚,内存是几十K几十K的增加。

5、读取数据,Hibernate的List速度很快,因为他是一次性把数据取完,这一点从观察任务管理器的java进程占用内存的变化也可以看得很清楚,内存几乎是10M的10M的增加。

6、JDBC读取数据的方式和Hibernate的List方式是一样的(这跟JDBC驱动有很大关系,不同的JDBC驱动,结果会很不一样),这从观察java进程内存变化可以判断出来,由于JDBC不需要像Hibernate那样构造一堆Cat对象实例,所以占用JVM内存要比Hibernate的List方式大概少一半左右。

7、Hibernate的Iterator方式并非一无是处,它适合于从大的结果集中选取少量的数据,即不需要占用很多内存,又可以迅速得到结果。另外Iterator适合于使用JCS缓冲。

上述的测试结果和结论不具备普遍适用性,仅供参考,并且也不能作为任何软件性能好坏的依据。实际上我认为影响测试结果最大的因素是JDBC驱动的选取,不同的JDBC驱动的实现会带来非常不同的结果。

上述测试结果均是取第2次到第4次运行结果取平均值,第1次运行结果不作为参考。

下面是测试用例:

Cat.java
--------

package com.fankai;

public class Cat {
private String id;
private String name;
private char sex;
private float weight;

public Cat() { }

public String getId() { return id; }
public void setId(String id) { this.id = id; }

public String getName() { return name; }
public void setName(String name) { this.name = name; }

public char getSex() { return sex; }
public void setSex(char sex) { this.sex = sex; }

public float getWeight() { return weight; }
public void setWeight(float weight) { this.weight = weight; }
}

-----------------------------------------------------

cat.hbm.xml
-----------

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping SYSTEM
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
<class name=
"com.fankai.Cat" table="cat">
<id name=
"id" unsaved-value="null">
<generator class=
"uuid.hex"/>
</id>
<property name=
"name" length="16" not-null="true"/>
<property name=
"sex" length="1" not-null="true"/>
<property name=
"weight" />
</class>
</hibernate-mapping>

-------------------------------------------------------------

JDBC 测试程序 TestCat.java
---------------------------

package com.fankai;

import java.sql.*;
import org.apache.log4j.*;

public class TestCat {

final private static Logger log = Logger.getLogger(TestCat.class);

public static void testCreate(int count) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(
"jdbc:mysql://localhost/hibernate?useUnicode=true&characterEncoding=GBK","hibernate","hibernate");
System.out.println(
"Start Creating Records with JDBC...");
long t0 = System.currentTimeMillis();
conn.setAutoCommit(false);
pstmt = conn.prepareStatement(
"insert into cat(id,name,sex,weight) values(?,?,?,?)");
for (int i=0; i< count; i++) {
pstmt.setString(1,String.valueOf(System.currentTimeMillis()+i));
//pstmt.setString(1,String.valueOf(i));
pstmt.setString(2,
"Princess"+i);
pstmt.setString(3,
"F");
pstmt.setFloat(4,7.4f);
pstmt.addBatch();
/*

pstmt.setString(1,String.valueOf(System.currentTimeMillis()+i+1));
pstmt.setString(2,"Sophie"+i);
pstmt.setString(3,"F");
pstmt.setFloat(4,4.1f);
pstmt.addBatch();

pstmt.setString(1,String.valueOf(System.currentTimeMillis()+i+2));
pstmt.setString(2,"Max"+i);
pstmt.setString(3,"M");
pstmt.setFloat(4,8.1f);
pstmt.addBatch();
*/

}
pstmt.executeBatch();
pstmt.close();
conn.commit();
long t1 = System.currentTimeMillis();
System.out.println(
"Finished Creating Records with JDBC: "+ (t1-t0)+"ms");
} catch (Exception e) {
log.error(e.getMessage());
} finally {
if (conn != null)
try {
conn.close();
} catch (Exception e) {}
}
}

public static void testReadAll() {
Connection conn = null;
PreparedStatement pstmt = null;
try {
Class.forName(
"com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(
"jdbc:mysql://localhost/hibernate?useUnicode=true&characterEncoding=GBK","hibernate","hibernate");
System.out.println(
"Start Reading Records with JDBC...");
long t0 = System.currentTimeMillis();
pstmt = conn.prepareStatement(
"select * from cat");
ResultSet rset = pstmt.executeQuery();
while (rset.next()) {
String id = rset.getString(1);
String name = rset.getString(2);
String sex = rset.getString(3);
float weigth = rset.getFloat(4);
}
rset.close();
pstmt.close();
long t1 = System.currentTimeMillis();
System.out.println(
"Finished Reading Records with JDBC: "+ (t1-t0)+"ms");
} catch (Exception e) {
log.error(e.getMessage());
} finally {
if (conn != null)
try {
conn.close();
} catch (Exception e) {}
}
}

}

----------------------------------------------------------------

Hibernate 测试用例:TestCatHibernate.java
-----------------------------------------
package com.fankai;

import java.util.*;
import net.sf.hibernate.*;
import org.apache.log4j.*;

public class TestCatHibernate {

final private static Logger log = Logger.getLogger(TestCatHibernate.class);

public static void testCreate(int count) {
SessionFactory sf = null;
Session s = null;
Transaction tx = null;
Cat c = null;
try {
sf = HibernateSessionFactory.getSessionFactory();
s = sf.openSession();
System.out.println("Start Creating Records with Hibernate...");
long t0 = System.currentTimeMillis();
tx = s.beginTransaction();
for (int i=0; i< count; i++) {
c = new Cat();
//c.setId(String.valueOf(i));
c.setName("Princess"+i);
c.setSex('F');
c.setWeight(7.4f);
s.save(c);

c = new Cat();
c.setName("Sophie"+i);
c.setSex('F');
c.setWeight(4.1f);
s.save(c);

c = new Cat();
c.setName("Max"+i);
c.setSex('M');
c.setWeight(8.1f);
s.save(c);

}
s.flush();
tx.commit();
long t1 = System.currentTimeMillis();
System.out.println("Finished Creating Records with Hibernate: "+ (t1-t0)+"ms");
} catch (HibernateException e) {
log.error(e.getMessage());
} finally {
if (s != null)
try {
s.close();
} catch (Exception e) {}
}
}

public static void testReadAll() {
SessionFactory sf = null;
Session s = null;
Cat c = null;
try {
sf = HibernateSessionFactory.getSessionFactory();
s = sf.openSession();
System.out.println("Start Reading Records with Hibernate...");
long t0 = System.currentTimeMillis();

Query q = s.createQuery("from Cat as c");

Iterator iter = q.iterate();
while (iter.hasNext()) {
c = (Cat) iter.next();
}

/*
List l = q.list();
for (int i=0; i< l.size(); i++) {
c = (Cat) l.get(i);
}
*/
long t1 = System.currentTimeMillis();
System.out.println("Finished Reading Records with Hibernate: "+ (t1-t0)+"ms");
} catch (HibernateException e) {
log.error(e.getMessage());
} finally {
if (s != null)
try {
s.close();
} catch (Exception e) {}
}
}

}
-----------------------------------------------------------------

主程序Main.java:
----------------
package com.fankai;

import net.sf.hibernate.*;
import org.apache.log4j.*;

public class Main {

final private static Logger log = Logger.getLogger(Main.class);

public static void main(String[] args) throws Exception {
//TestCatHibernate.testCreate(Integer.parseInt(args[0]));
//TestCat.testCreate(Integer.parseInt(args[0]));
TestCat.testReadAll();
//TestCatHibernate.testReadAll();
}
}
---------------------------------------------------------------


Hibernate的Singleton模式生成SessionFactory的工具类:
--------------------------------------------------
package com.fankai;

import net.sf.hibernate.cfg.Configuration;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Session;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.MappingException;

public class HibernateSessionFactory {

private static SessionFactory sf = null;

public static synchronized SessionFactory getSessionFactory() throws HibernateException {
Configuration conf = null;
if (sf == null) {
try {
conf = new Configuration().addClass(Cat.class);
} catch (MappingException e) {
System.out.println(e.getMessage());
return null;
}
sf = conf.buildSessionFactory();
}
return sf;
}

public static Session openSession() throws HibernateException {
return getSessionFactory().openSession();
}
}
------------------------------------------------------------------

ant 编译运行脚本build.xml:
--------------------------
<?xml version="1.0" encoding="GBK" ?>

<project default="run" basedir=".">

<property name="base" value="." />
<property name="src" value="src" />
<property name="lib" value="lib" />
<property name="build" value="classes" />

<path id="classpath">
<fileset dir="${lib}">
<include name="*.jar"/>
</fileset>
<pathelement location="${build}"/>
</path>

<target name="build">
<javac classpathref="classpath" srcdir="${src}" destdir="${build}">
<include name="**/*.java" />
</javac>
</target>

<target name="run" depends="build">
<java classname="com.fankai.Main" fork="yes">
<classpath refid="classpath"/>
<arg value="1000"/>
<jvmarg line="-Xms256m -Xmx256m" />
</java>
</target>

<target name="ide" >
<java classname="net.sf.hibern8ide.Hibern8IDE" fork="true">
<classpath refid="classpath"/>
</java>
</target>

</project>


ant脚本没有贴上去,再贴一次:

<?xml version="1.0" encoding="GBK" ?>

<project default=
"run" basedir=".">

<property name=
"base" value="." />
<property name=
"src" value="src" />
<property name=
"lib" value="lib" />
<property name=
"build" value="classes" />

<path id=
"classpath">
<fileset dir=
"${lib}">
<include name=
"*.jar"/>
</fileset>
<pathelement location=
"${build}"/>
</path>

<target name=
"build">
<javac classpathref=
"classpath" srcdir="${src}" destdir="${build}">
<include name=
"**/*.java" />
</javac>
</target>

<target name=
"run" depends="build">
<java classname=
"com.fankai.Main" fork="yes">
<classpath refid=
"classpath"/>
<arg value=
"1000"/>
<jvmarg line=
"-Xms256m -Xmx256m" />
</java>
</target>

<target name=
"ide" >
<java classname=
"net.sf.hibern8ide.Hibern8IDE" fork="true">
<classpath refid=
"classpath"/>
</java>
</target>

</project>

还有一个值得注意的问题就是,不要把所有的测试项目放在一个主程序里面一次测试完成,因为我发现前面的测试项目会对下面的测试项目产生影响,会加快下面测试项目执行速度,影响测试结果的真实性。所以我宁可麻烦一点,每次修改程序代码,注释掉不执行的项目,让每一个项目单独执行一遍。

ant脚本再贴一次:

<?xml version="1.0" encoding="GBK" ?>

<project default=
"run" basedir=".">

<property name=
"base" value="." />
<property name=
"src" value="src" />
<property name=
"lib" value="lib" />
<property name=
"build" value="classes" />

<path id=
"classpath">
<fileset dir=
"${lib}">
<include name=
"*.jar"/>
</fileset>
<pathelement location=
"${build}"/>
</path>

<target name=
"build">
<javac classpathref=
"classpath" srcdir="${src}" destdir="${build}">
<include name=
"**/*.java" />
</javac>
</target>

<target name=
"run" depends="build">
<java classname=
"com.fankai.Main" fork="yes">
<classpath refid=
"classpath"/>
<arg value=
"1000"/>
<jvmarg line=
"-Xms256m -Xmx256m" />
</java>
</target>

<target name=
"ide" >
<java classname=
"net.sf.hibern8ide.Hibern8IDE" fork="true">
<classpath refid=
"classpath"/>
</java>
</target>

</project>

做完这个测试以后,测试结果相当出乎我的意料之外,我把测试用例修改了一下,加了一些测试,测试结果让我越来越疑惑,我逐渐感觉到MySQL的JDBC驱动有很大的问题,如果我这个想法属实的话,那么上面的那些测试结果和结论统统都是胡扯,没有任何意义,是误导,极其有害,在这里,我郑重的宣布上面的结论统统无效。

我发现MySQL的JDBC驱动会忽略setFetchSize,也就是说它总是一股脑把所有的记录统统的从数据库取出来。但是按照我的理解,标准的JDBC的做法不应该如此,而应该是只取出setFetchSize指定的记录数,当不够用的时候,再次向数据库取FetchSize个记录数。也就是说,假设从数据库中取30万条记录的结果集,假设默认的FetchSize是1000的话,应该实际上只从数据库中取1000条记录,等到这1000条不够用的时候,再从数据库中取出下1000条记录。这样兼顾了速度和内存使用。但是MySQL不管我怎么设FetchSize,总是1次性把30万条记录统统取到内存中来,这就造成了为什么峰值内存能够达到70MB的原因。而我的MySQL表空间文件占用的硬盘空间大小是66MB,我的数据库中没有别的什么数据,几乎可以粗略的判断正好是把30万条记录统统读入内存。

我相信在Oracle,DB2的这样的重量级数据库以及官方JDBC驱动下做同样的测试,JDBC Reading速度不应该有如此之快,也不应该需要如此多的内存,应该可以根据setFetchSize的调节,在内存占用和速度之间取得一个平衡,要速度就必须多耗内存,要省内存就必须牺牲一定的速度,极端情况下就是完全不顾及内存消耗,只满足速度要求,这就是MySQL的做法,但是这种做法实在是非常糟糕,MySQL的JDBC驱动实在是太烂了!!!

按照我的想法和理解,Hibernate Iterator应该是标准的JDBC Result的封装,速度应该不会和JDBC有如此巨大的差距,应该就像上面楼主的测试结果一样,大概是1半的速度,这样比较正常。但是在MySQL上有了不是一个数量级的差距,问题很怪异。

我又做了一个测试,依然查询30万条记录,但是只取前100条记录,测试结果:

JDBC: 4.9秒
Hibernate List: 24秒
Hibernate Iterator: 3.4秒

Hibernate List的速度是意料中的事情,因为它是一次从数据库中取出30万条记录构造结果集(主要的时间消耗在这里),所以对它来说,从结果集中再去取100条和取30万几乎没有时间上的差别。峰值内存消耗160MB。

JDBC节省了不少时间,但仍然消耗峰值70MB内存,我再进一步跟踪每一步的时间消耗,发现构造30万条记录的结果集大概消耗4.8秒,取100条记录只有40ms,而再进一步测试,跟踪取30万条记录的时间大概是4秒左右。

而Hibernate Iterator最令人意外,只花了3.4秒,并且峰值消耗内存只有50MB,进一步跟踪发现构造结果集时间是3.4秒左右,取100条记录花不到100ms,取1000条记录花2.4秒。

上面的测试说明了以下的问题:

1、JDBC和Hibernate List都是先把30万条记录都从数据库中取出来,然后再进行内存操作,所以主要的时间消耗都花在构造结果集上,并且内存消耗非常大,几乎是把整个30万条记录全部装入内存。

2、Hibernate Iterator并没有把30万条记录都装入内存,应该只是装入部分,所以内存消耗比JDBC还要少20MB,它的构造结果集的时间比JDBC少,主要的时间开销在结果集的遍历上。

3、
构造结果集(30万条)的时间排名:
Hibernate Iterator(3.4s) < JDBC(4.8s) < Hibernate List (22s)

遍历结果集(30万)的时间排名:
Hibernate List(不到100ms) < JDBC(4s) < Hibernate Iterator (N/A)

内存消耗排名(30万条):
Hibernate Iterator(50MB) < JDBC(70MB) < Hibernate List(160MB)

结论:
由于MySQL的JDBC驱动的重大缺陷,使得测试结果变得毫无意义,不具备任何参考价值,只是我们能够大概判断出一些结论:
一、精心编写的JDBC无论如何都是最快的。
二、Hibernate List和Iterator适用的场合不同,不存在孰优孰劣的问题

我个人认为Hibernate Iterator是JDBC Result的封装,Hibernate List是Scrollable Result的封装,所以我推测,如果在Oracle或者DB2上面做同样的Read测试,如果结果集小于FetchSize,4者在速度上应该都不会有差别;如果结果集大于FetchSize的话,但是不是FetchSize的很多倍,速度排名应该是:
JDBC Scrollable Result (消耗时间最少) < Hibernate List < JDBC Result < Hibernate Iterator

如果结果集非常大,但是只取结果集中的部分记录,那么速度排名:
JDBC Result < Hibernate Iterator < JDBC Scrollable Result < Hibernate List

修改后的测试用例:

package com.fankai;

import java.sql.*;
import org.apache.log4j.*;

public class TestCat {

final private static Logger log = Logger.getLogger(TestCat.class);

public static void testCreate(int count) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(
"jdbc:mysql://localhost/hibernate?useUnicode=true&characterEncoding=GBK","hibernate","hibernate");
System.out.println(
"Start Creating Records with JDBC...");
long t0 = System.currentTimeMillis();
conn.setAutoCommit(false);
pstmt = conn.prepareStatement(
"insert into cat(id,name,sex,weight) values(?,?,?,?)");
for (int i=0; i< count; i++) {
pstmt.setString(1,String.valueOf(System.currentTimeMillis()+i));
//pstmt.setString(1,String.valueOf(i));
pstmt.setString(2,
"Princess"+i);
pstmt.setString(3,
"F");
pstmt.setFloat(4,7.4f);
pstmt.addBatch();
/*

pstmt.setString(1,String.valueOf(System.currentTimeMillis()+i+1));
pstmt.setString(2,"Sophie"+i);
pstmt.setString(3,"F");
pstmt.setFloat(4,4.1f);
pstmt.addBatch();

pstmt.setString(1,String.valueOf(System.currentTimeMillis()+i+2));
pstmt.setString(2,"Max"+i);
pstmt.setString(3,"M");
pstmt.setFloat(4,8.1f);
pstmt.addBatch();
*/

}
pstmt.executeBatch();
pstmt.close();
conn.commit();
long t1 = System.currentTimeMillis();
System.out.println(
"Finished Creating Records with JDBC: "+ (t1-t0)+"ms");
} catch (Exception e) {
log.error(e.getMessage());
} finally {
if (conn != null)
try {
conn.close();
} catch (Exception e) {}
}
}

public static void testReadAll(int count) {
Connection conn = null;
PreparedStatement pstmt = null;
//Cat c = null;
try {
Class.forName(
"com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(
"jdbc:mysql://localhost/hibernate?useUnicode=true&characterEncoding=GBK","hibernate","hibernate");
System.out.println(
"Start Reading Records with JDBC...");
long t0 = System.currentTimeMillis();
pstmt = conn.prepareStatement(
"select * from cat");
pstmt.setFetchSize(1000);
System.out.println(
"Fetch Size: " + pstmt.getFetchSize());
ResultSet rset = pstmt.executeQuery();
for (int i=0; rset.next() && (i< count); i++) {
Cat c = new Cat();
c.setId(rset.getString(1));
c.setName(rset.getString(2));
c.setSex(rset.getString(2).toCharArray()[0]);
c.setWeight(rset.getFloat(4));
}
rset.close();
pstmt.close();
long t1 = System.currentTimeMillis();
System.out.println(
"Finished Reading Records with JDBC: "+ (t1-t0)+"ms");
} catch (Exception e) {
log.error(e.getMessage());
} finally {
if (conn != null)
try {
conn.close();
} catch (Exception e) {}
}
}

}

package com.fankai;

import java.util.*;
import net.sf.hibernate.*;
import org.apache.log4j.*;

public class TestCatHibernate {

final private static Logger log = Logger.getLogger(TestCatHibernate.class);

public static void testCreate(int count) {
SessionFactory sf = null;
Session s = null;
Transaction tx = null;
Cat c = null;
try {
sf = HibernateSessionFactory.getSessionFactory();
s = sf.openSession();
System.out.println("Start Creating Records with Hibernate...");
long t0 = System.currentTimeMillis();
tx = s.beginTransaction();
for (int i=0; i< count; i++) {
c = new Cat();
//c.setId(String.valueOf(i));
c.setName(
"Princess"+i);
c.setSex('F');
c.setWeight(7.4f);
s.save(c);

c = new Cat();
c.setName(
"Sophie"+i);
c.setSex('F');
c.setWeight(4.1f);
s.save(c);

c = new Cat();
c.setName(
"Max"+i);
c.setSex('M');
c.setWeight(8.1f);
s.save(c);

}
s.flush();
tx.commit();
long t1 = System.currentTimeMillis();
System.out.println(
"Finished Creating Records with Hibernate: "+ (t1-t0)+"ms");
} catch (HibernateException e) {
log.error(e.getMessage());
} finally {
if (s != null)
try {
s.close();
} catch (Exception e) {}
}
}

public static void testReadAll(int count) {
SessionFactory sf = null;
Session s = null;
//Cat c = null;
try {
sf = HibernateSessionFactory.getSessionFactory();
s = sf.openSession();
log.info(s);
System.out.println(
"Start Reading Records with Hibernate...");
long t0 = System.currentTimeMillis();

Query q = s.createQuery(
"from Cat as c");

long t01 = System.currentTimeMillis();
Iterator iter = q.iterate();
long t02 = System.currentTimeMillis();
for (int i=0; iter.hasNext() && (i< count); i++) {
Cat c = (Cat) iter.next();
}
/*
List l = q.list();
long t02 = System.currentTimeMillis();
for (int i=0; (i< l.size()) && (i< count); i++) {
Cat c = (Cat) l.get(i);
}
*/

long t1 = System.currentTimeMillis();
System.out.println(t01-t0);
System.out.println(t02-t01);
System.out.println(t1-t02);
System.out.println(
"Finished Reading Records with Hibernate: "+ (t1-t0)+"ms");
} catch (HibernateException e) {
log.error(e.getMessage());
} finally {
if (s != null)
try {
s.close();
} catch (Exception e) {}
}
}

}

package com.fankai;

import net.sf.hibernate.*;
import org.apache.log4j.*;

public class Main {

final private static Logger log = Logger.getLogger(Main.class);

public static void main(String[] args) throws Exception {
//TestCatHibernate.testCreate(Integer.parseInt(args[0]));
//TestCat.testCreate(Integer.parseInt(args[0]));
//TestCat.testReadAll(Integer.parseInt(args[0]));
TestCatHibernate.testReadAll(Integer.parseInt(args[0]));
}
}

to ROBBIN:

你真的很牛B啊

一上来就说人家程序有问题,又说人家测试没有用

非常抱歉,恕我眼拙,从贴出的代码我实在看不出来哪里编译不能通过

再看看你做的测试

你是在做压力测试?还是性能测试?一次取30万条记录?你不妨查查任何数据库的官方手册,哪一个会推荐你这么做?如果是压力测试,那还情有可原,不过在这里,似乎不是吧

在工业环境下的性能测试,是必须符合实际情况的,你曾经做过的项目有一次取回30万条记录的功能?如果有,那我只能说I 服了 U。

虽然你说的没错,HIBERNATE 的总体性能较之相应的JDBC有所欠缺,但是请注意,JDBC本身是没有缓存的,而HIBERNATE对缓冲做了处理,所以从某种程度上来说,HIBERNATE的实用性能高于JDBC。

我也赞同不要轻易做这方面的测试,不过我觉得你对这为提问者没有足够的尊重,他的目的是来探求结论的,虽然他所使用过程或许你不以为然,但你也没必要一棍子打死吧?


hehe ,终于也有人出刀了。

说句题外话,我也不认为此测试与彼得失有何根本得本质得改进。

把所有都贴出来,声明测试得硬件软件配置,对于大家交流来说意义也不大。

大家测得时候肯定都是在同一个环境下,大家只是关心问题所在和相对得测试得结果罢了。