另外设置
hibernate.show_sql=true

这样你可以看到Hibernate实际实现的SQL语句是否和你的JDBC一致。

等待你的结果。

肯定类似
select post0_.attr1 as attr10_, post0_.attr2 as attr20_ from post post0_ limit ?, ?

Oh My God!!! 我犯了想当然的错误! 原来Hibernate这么贴心,真的是使用limit进行分页。

另外,JDBC的Object组装基本上不消耗时间,主要是内存消耗,我以前做30万条记录测试的时候,就发现Object组装与否,几乎测量不出差别。

我用MySQL的测试结果如下:

MySQL数据库表Cat,表记录3万条,从第10000条记录开始,取100条记录出来

Hibernate: 平均60ms
JDBC: 平均30ms

Oh My God!!! 我犯了想当然的错误! 原来Hibernate这么贴心,真的是使用limit进行分页。

另外,JDBC的Object组装基本上不消耗时间,主要是内存消耗,我以前做30万条记录测试的时候,就发现Object组装与否,几乎测量不出差别。

我用MySQL的测试结果如下:

MySQL数据库表Cat,表记录3万条,从第10000条记录开始,取100条记录出来

Hibernate List : 平均60ms
JDBC: 平均30ms

噢,对喽,我的测试代码片断
JDBC:


System.out.println("Start Reading Records with JDBC...");
long t0 = System.currentTimeMillis();
pstmt = conn.prepareStatement(
"select * from cat limit 10000,100");
ResultSet rset = pstmt.executeQuery();
for (int i=0; i< 100; i++) {
rset.next();
Cat c = new Cat();
c.setId(rset.getString(1));
c.setName(rset.getString(2));
c.setSex(rset.getString(3).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");

Hibernate List:


long t0 = System.currentTimeMillis();

Query q = s.createQuery("from Cat as c");
q.setFirstResult(10000);
q.setMaxResults(100);

List l = q.list();
for (int i=0; i< 100; i++) {
Cat c = (Cat) l.get(i);
}

long t1 = System.currentTimeMillis();
System.out.println(
"Finished Reading Records with Hibernate: "+ (t1-t0)+"ms");

应该不需要再


for (int i=0; i< 100; i++) { Cat c = (Cat) l.get(i);}

了吧,
List l = q.list();时hibernate就会遍历ResultSet并组装每个对象

的确不需要的,主要是为了做一个对比,两个程序都把每个VO列出来做对比。对于Hibernate来说,这个内存循环几乎没有时间开销,不影响测试结果。

to yehs220
<<<只要在hibernate.properties中设置了
hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
分页时就会采用limit>>>

那我肯定是指定了MySQLDialect,并且hibernate也采用了分页,但是速度相差很多

sql = "select post from com.my.test.dbo.Post as post ";
long begintime = System.currentTimeMillis();
System.out.println("Begin time is " + begintime);
query = session.createQuery(sql);
query.setFirstResult(10000);
query.setMaxResults(100);

出来的sql是
select post.id as id, post.userid as userid, post.topic as topic from post post
打出来的sql是这样的,好象没有分页啊(limit)

to robin
是不是mysql有这种取巧的sql,所以速度快很多

to banq

出来的sql是
select post.id as id, post.userid as userid, post.topic as topic from post ... post


我的hibernte版本是h2.0.5 b

你的Hibernate版本比我的都高,我用的还是Hibernate2.01。我的Hibernate打印出来的sql也是用了limit的。建议你换2.03稳定版试试看。

配置:


hibernate.dialect net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class com.mysql.jdbc.Driver
hibernate.connection.url jdbc:mysql://localhost/hibernate?useUnicode=true&characterEncoding=GBK
hibernate.connection.username hibernate
hibernate.connection.password hibernate

我原来是准备用hibernate 查询所有记录的ID,看来还是用JDBC最快,因为我的目的也是追求性能第一。

在我的一个项目中,数据新增、更新都已经使用了CMP+CMR,本来批量查询准备使用DAO+Hibernate。

但是由于我的项目设计是:先通过DAO从数据库获得一个页面上的数据对象的ID集合,然后在Web层对这个ID集合遍历时,根据ID先从Web层缓存中获得完整的数据对象Java Object,如果缓存没有,再通过DAO从数据库根据ID获得数据对象。

在这整个环节中,看来只有“根据ID查询数据库时”可以使用一下Hibernate的load查询方法,其它没地方可以用了。但是想想,为了一次查询,要配置mapping.xml,要在运行时load那么多Hibernate类。

我是有些苦笑不得了。

你的这个需求特别特别适合于用 Hibernate Iterator + JCS 来做,因为这些缓存的问题Hibernate都透明的帮你做掉了,你不需要手工编写缓存的管理代码。

不过如果你已经有了自己成熟的解决问题的框架,到是没有必要用Hibernate,毕竟需要配置一堆hbm,有点麻烦。

是啊,使用Hibernate Iterator + JCS 又碰到缓冲不能共享的问题。

因为我已经对Java Object实现了缓存,但是如果使用Hibernate的缓存,一则它的缓存是在EJB层的,二则,它的缓存不能和我共享啊,一个Java Object有两份缓存,一个是在我的缓存系统,一个是在Hibernate的缓存系统。

我决定就这么用吧,查询单个数据对象时,使用Hibernate,查询所有ID集合时用JDBC,这种用法有最大的好处:方便。

查询单个数据对象时,因为使用Hibernate,不用setXXX每个字段了;
查询ID集合时,使用的是最简单的SQL语句,至少我可以在DBA上测试一下SQL语句的正确性,这样在性能 和 健壮性方面都比使用Hibernate强。

唯一缺点是,DB Pool我要配置三个,CMP的、Hibernate的和直接的JDBC Datasource

Hibernate有个Swing的GUI工具叫做Hibernate8IDE,是专门供开发的时候调试HQL的,一个很简单,但是很方便的东西,对于HQL没有信心的人来说,必备的工具。

http://www.xam.dk/hibern8ide/hibern8ide.swf

这里是一个演示,教你怎么用Hibernate8IDE的,很简单,还可以使用鼠标拖动的方式来生成HQL。

我总觉得60ms vs 30ms的差距还是太大了,

在我的机器上hibernate比jdbc大约差了20%