但如果缓存中不存在数据有可以能出现N+1问题
====================
*
* 在默认情况下list每次都会向数据库发出查询对象的sql!用list()就应该可以及时刷新吧,使用query,但list默认情况下不会利用缓存!
实体对象查询
* N + 1问题,list会向缓存中放入数据!你应该是用的iterate吧: 首先发出一条查询对象id列表的sql
N,在默认情况下,如果缓存中不存在与之匹配的数据,而再次发出sql
*
* 默认情况下,那么会根据id发出相应的sql语句
* list和iterate的区别,有可以能出现N+1问题
所谓的N+1是在查询的时候发出了N+1条sql语句
1,除非配置查询缓存.iterate查询:在默认情况下iterate利用缓存数据,所以下面的list操作
* 虽然在一级缓存中已经有了对象数据,list会向缓存中放入数据: 根据id列表到缓存中查询这就是你在现实客户端信息的时候采用的查询方式不正确了吧,但不会利用数据
*
*/,而不利用缓存中的数据
* iterate?
* list每次都会发出sql语句
但我觉得其中最好的办法是用criteria的fetchmode来解决,但是hibernate in action中写的很不详细。我昨晚试了好长时间来的到答案。下面总结一下。 需求这样的,我有四张表(one,two,three,four)从one一直外键关联到four。结构如下
现在在session中得到one,并从one里一直取到four里的内容。如果简单的用session.get来实现是这样的。 java代码查看源代码打印01.one one = (one)session.get(one.class,new integer(1));02. 03.iterator iterone = one.gettwos().iterator();04. 05.while(iterone.hasnext()){06. 07.two two = (two) iterone.next();08. 09.iterator itertwo = 10.two.getthrees().iterator();11. 12.while(itertwo.hasnext()){13. 14.three three = (three) itertwo.next();15.three.getfours().size(); 16. 17.}18. 19.} 这样我在session关闭后返回的one里是从one到four的信息都有的。
然而这样做所导致的结果是生成大量的sql查询,这是一个典型的n+1 selects问题。如果系统结构层次多,符合条件的记录多,那么hibernate为你生成的sql查询将是难以接受的。
对于这个例子生成的sql是这样的
sql代码查看源代码打印01.hibernate: select one0_.c_one_id as c1_0_, 02.one0_.c_one_text as c2_3_0_ from one one0_ where03.one0_.c_one_id=?04. 05.hibernate: select twos0_.c_one_id as c2_1_, 06.twos0_.c_two_id as c1_1_, twos0_.c_two_id as c1_0_,07.twos0_.c_one_id as c2_2_0_, twos0_.c_two_text as08.c3_2_0_ from two twos0_ where twos0_.c_one_id=?09. 10.hibernate: select threes0_.c_two_id as c2_1_, 11.threes0_.c_three_id as c1_1_, threes0_.c_three_id 12.as c1_0_, threes0_.c_two_id as c2_1_0_, 13.threes0_.c_three_text as c3_1_0_ from three 14.threes0_ where threes0_.c_two_id=?15. 16.hibernate: select fours0_.c_three_id as c2_1_, 17.fours0_.c_four_id as c1_1_, fours0_.c_four_id as18.c1_0_, fours0_.c_three_id as c2_0_0_, 19.fours0_.c_four_text as c3_0_0_ from four fours0_ 20.where fours0_.c_three_id=?21. 22.hibernate: select fours0_.c_three_id as c2_1_, 23.fours0_.c_four_id as c1_1_, fours0_.c_four_id as c1_0_, fours0_.c_three_id as c2_0_0_, 24.fours0_.c_four_text as c3_0_0_ from four fours0_ 25.where fours0_.c_three_id=?26. 27.hibernate: select threes0_.c_two_id as c2_1_, 28.threes0_.c_three_id as c1_1_, threes0_.c_three_id 29.as c1_0_, threes0_.c_two_id as c2_1_0_, 30.threes0_.c_three_text as c3_1_0_ from three 31.threes0_ where threes0_.c_two_id=?32. 33.hibernate: select fours0_.c_three_id as c2_1_,34.fours0_.c_four_id as c1_1_, fours0_.c_four_id as35.c1_0_, fours0_.c_three_id as c2_0_0_, 36.fours0_.c_four_text as c3_0_0_ from four fours0_ 37.where fours0_.c_three_id=?38. 39.hibernate: select fours0_.c_three_id as c2_1_,40.fours0_.c_four_id as c1_1_, fours0_.c_four_id as41.c1_0_, fours0_.c_three_id as c2_0_0_, 42.fours0_.c_four_text as c3_0_0_ from four fours0_ 43.where fours0_.c_three_id=? 对于这样的问题,在没有hibernate以前我们一般都用jdbc来做,那样的话我们其实用一个进行3次join
的sql语句就可以实现,但 是这样解决也有问题,就是返回的resultset中的数据非常多,而且杂乱,其实是从one到four平行排列的。对于这样的结果集我们要把它手动影射 曾对象结构也是一个很复杂的操作。 幸好hibernate3可以为我们做这些事情(我再一次被hibernate的强大所震撼)。 上面的实现可以用criteria来实现: java代码查看源代码打印01.session = sessionfactory.opensession();02. 03.criteria criteria = 04.session.createcriteria(one.class);05. 06.criteria.add(expression.eq("coneid",new07.integer(1)));08. 09.one = 10.(one)criteria.setfetchmode("twos",fetchmode.join).11.setfetchmode("twos.threes",fetchmode.join).12.setfetchmode("twos.threes.fours",fetchmode.join).13.uniqueresult();14. 15.session.close(); 这里的重点是这句话
criteria.setfetchmode("twos",fetchmode.join).setfetchmode("twos.threes",fetchmode.join).setfetchmode("twos.threes.fours",fetchmode.join).uniqueresult(); 在用criteria之前先设置fetchmode,应为criteria是动态生成sql语句的,所以生成的sql就是一层层join下去的。 setfetchmode(string,mode)第一个参数是association path,用"."来表示路径。这一点具体的例子很少,文档也没有写清楚。我也是试了很久才试出来的。 就这个例子来所把因为取道第四层,所以要进行三次setfetchmode 第一次的路径是twos,一位one中有two的set。这个具体要更具hbm.xml的配置来定。 第二个路径就是twos.threes 第三个就是twos.threes.fours 一次类推,一层层增加的。 这样做法最终生成的sql是这样的: sql代码查看源代码打印01.hibernate: select this_.c_one_id as c1_3_, 02.this_.c_one_text as c2_3_3_, twos2_.c_one_id as c2_5_, 03.twos2_.c_two_id as c1_5_, twos2_.c_two_id as c1_0_, 04.twos2_.c_one_id as c2_2_0_, twos2_.c_two_text as05.c3_2_0_, threes3_.c_two_id as c2_6_, 06.threes3_.c_three_id as c1_6_, threes3_.c_three_id as07.c1_1_, threes3_.c_two_id as c2_1_1_, 08.threes3_.c_three_text as c3_1_1_, fours4_.c_three_id 09.as c2_7_, fours4_.c_four_id as c1_7_, 10.fours4_.c_four_id as c1_2_, fours4_.c_three_id as11.c2_0_2_, fours4_.c_four_text as c3_0_2_ from one this_ 12.left outer join two twos2_ on13.this_.c_one_id=twos2_.c_one_id left outer join three 14.threes3_ on twos2_.c_two_id=threes3_.c_two_id left15.outer join four fours4_ on16.threes3_.c_three_id=fours4_.c_three_id where17.this_.c_one_id=? 虽然很长但是只有一条sql语句。性能要好很多。hibernate的强大之处是它会把返回的resultset自动
影射到你的对象模型里面去。这就为我们省了很多事。
用户登录
还没有账号?立即注册
用户注册
投稿取消
| 文章分类: |
|
还能输入300字
上传中....
簡單_噺