之前用JdbcTemplate多一点,Hibernate用得少,最近开发的一个工作流引擎用到了它,也遇到了一些问题,在这里总结一下:
1. Hibernate的写数据库操作必需起事务
虽然个人认为这不是必要的,也做了一点尝试,试图不起事务,让Hibernate能写入数据,不过还是失败了。
2. Hibernate Session不适合存放过多的对象
Hibernate操作过的对象都会保存在Session中,我试过在一个Hibernate Session中保存几千个对象,结果原来只需要300毫秒的操作变成了要10秒钟才能完成,原来还以为是事务太大导致性能下降,经过拆分事务后情况并没有改善,最终发现是Hibernate Session的问题。这可以通过session.clear()或者session.evict()清除session里的对象。
3. OpenSessionInViewFilter会阻止Session自动关闭
Hibernate在与Spring整合使用时,默认是开启session autoClose功能的,即事务提交时Hibernate Session也会关闭,这样在一定程序上就可以避免上面所说的Session中对象过多的问题,但是前面也说过,我经过拆分事务后关没有改善。网上查过后发现原来是OpenSessionInViewFilter搞的鬼,它会在第一次请求时都创建一个Session,直到请求完成后才关闭,这样Spring就会将这个session直接拿来用给事务使用,事务提交时也不会自动关闭这个session,所以我虽然在一个请求中将事务拆分成多个,但是session由始至终只有一个。最后把OpenSessionInViewFilter去掉,问题顺利解决。
4. Hibernate二级缓存可以使对象跨Session使用
虽然不用二级缓存,也可以通过entity.update()或者entity.merge()方法将一个对象放到当前session中使用,但是这样会多一条update或者select语句,还是有一些性能损耗,如果用了二级缓存就完全不会读写数据库
5. Hibernate二级缓存对HQL没有效果
正如Hiberate的文档所说,它的二级缓存是基于主键Hash保存的,原理上和NoSQL数据库接近,所以当使用Hibernate的Query进行HQL条件查询时,二级缓存的数据是起不了作用的,只有用get和load这样通过主键查询的方法时才会生效,所以如果要充分利用二级缓存,可以考虑使用二次查询,第一步先select id from Entity where <condition>查出满足条件的主键,第二步再用session.get(id)获得对象