古怪的Hibernate性能问题- -| 回首页 | 2004年索引 | - -不得不服

Hibernate性能问题解决- -

                                      

古怪的Hibernate性能问题:
http://www.blogdriver.com/showBlog.do?diaryID=204604
 
Session.find方法开始一路跟踪,很快就发现AbstractEntityPersister.setPropertyValues方法耗用了最多的时间。该方法代码如下:
 
 public void setPropertyValues(Object object, Object[] values) throws HibernateException {
  try{
   if (optimizer!=null) {
    optimizer.setPropertyValues(object, values);  // 1
    return;
   } 
  }
  catch (Throwable t) {
   throw new PropertyAccessException(
    t,
    ReflectHelper.PROPERTY_ACCESS_EXCEPTION,
    true,
    mappedClass,
    ReflectHelper.getPropertyName(t, optimizer)
   );
  }
  
  for (int j=0; j<getHydrateSpan(); j++) getSetters()[j].set(object, values[j]);  // 2
 }

其中“2”的地方效率相当低,给一个实体对象的25个属性赋值大约需要半秒到一秒。把这里的循环拆开跟踪,发现因为password属性的getter/setter需要对密码加密/解密,并且每一次加密/解密时都重新初始化加密器(Cipher对象),造成了巨大的损耗。把初始化代码抽取出来,再添加一些缓存,性能提升一倍左右,但仍然很慢,比在Sun JDK下运行慢一个数量级左右。
 
再观察之下,发现某些对象从数据库中取出时执行了“1”的代码,而效率低下的部分都执行到了“2”。也就是说,Party类的persister没有得到optimizer,所以只能通过反射给属性赋值。之所以在Sun JDK下执行仍然效率不减,估计是因为Sun JDK的反射机制做得比较好,IBM的做得比较烂。再观察Hibernate输出的日志,发现有一句说“PartysetXxxx方法是private,所以将optimizer禁用”。于是将这个方法改为public,再运行,速度飞快。问题圆满解决。最后解决问题的过程看起来就像是我把一个不相干的private方法改成public,然后效率就突然提升,不明就里的人恐怕会觉得有点神奇。
 
最后,有一个问题:在我看来,如果要给一个实体的属性设上值,唯一的办法就是用反射,通过Method对象去调用。但optimizer显然有另一种高效得多的实现,值得去研究一下。

- 作者: gigix 2004年06月18日, 星期五 20:34

Trackback

你可以使用这个链接引用该篇日志 http://publishblog.blogdriver.com/blog/tb.b?diaryID=205856

回复

- 评论人:打倒透明

Sat Jun 19 07:55:20 CST 2004 

爱你就是推倒再推倒

- 评论人:ghq7613

Fri Jun 18 21:02:14 CST 2004  作者邮箱 

    受益匪浅也,多多益善

评论内容: