Hibernate学习笔记四 查询
HQL语法
1、基本语法
String hql = " from com.yyb.domain.Customer ";//完整写法 String hql2 = " from Customer "; //简单写法 String hql3 = " from java.lang.Object ";//查询所有表
2、排序
//排序,和sql一样
String hql1 = " from Customer order by cust_id asc ";
3、条件
String hql1 = " from Customer where cust_id =? ";
String hql2 = " from Customer where cust_id = :id ";
4、分页
String hql1 = " from Customer ";//完整写法 Query query = session.createQuery(hql1); //limit ?,? // (当前页数-1)*每页条数 query.setFirstResult(2); query.setMaxResults(2);
5、聚合查询
String hql1 = " select count(*) from Customer ";
String hql2 = " select sum(cust_id) from Customer ";
String hql3 = " select avg(cust_id) from Customer ";
String hql4 = " select max(cust_id) from Customer ";
String hql5 = " select min(cust_id) from Customer ";
Query query = session.createQuery(hql5);
Number number = (Number) query.uniqueResult();
6、投影查询
String hql1 = " select cust_name from Customer "; String hql2 = " select cust_name,cust_id from Customer "; String hql3 = " select new Customer(cust_id,cust_name) from Customer ";//查询出来封装到对象中,必须有相应的构造函数和空参构造函数
7、多表查询
//回顾-原生SQL // 交叉连接-笛卡尔积(避免) // select * from A,B // 内连接 // |-隐式内连接 // select * from A,B where b.aid = a.id // |-显式内连接 // select * from A inner join B on b.aid = a.id // 外连接 // |- 左外 // select * from A left [outer] join B on b.aid = a.id // |- 右外 // select * from A right [outer] join B on b.aid = a.id //--------------------------------------------------------------------- //HQL的多表查询 //内连接(迫切) //外连接 // |-左外(迫切) // |-右外(迫切)
7.1内连接
//HQL 内连接 => 将连接的两端对象分别返回.放到数组中. public void fun1(){ Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); //---------------------------------------------------- String hql = " from Customer c inner join c.linkMens "; Query query = session.createQuery(hql); List<Object[]> list = query.list(); for(Object[] arr : list){ System.out.println(Arrays.toString(arr)); } //---------------------------------------------------- tx.commit(); session.close(); }
7.2迫切内连接,返回一个对象,另一个对象也被封装到了这个对象中。
@Test //HQL 迫切内连接 => 帮我们进行封装.返回值就是一个对象 public void fun2(){ Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); //---------------------------------------------------- String hql = " from Customer c inner join fetch c.linkMens "; Query query = session.createQuery(hql); List<Customer> list = query.list(); System.out.println(list); //---------------------------------------------------- tx.commit(); session.close(); }
7.3 左、右连接
String hql = " from Customer c left join c.linkMens ";
String hql = " from Customer c right join c.linkMens ";
Criteria语法
1、基本语法
Criteria c = session.createCriteria(Customer.class); List<Customer> list = c.list();
2、条件
Criteria c = session.createCriteria(Customer.class); // c.add(Restrictions.idEq(2l)); c.add(Restrictions.eq("cust_id",2l)); List<Customer> list = c.list();
3、分页
Criteria c = session.createCriteria(Customer.class); //limit ?,? c.setFirstResult(0); c.setMaxResults(2);
4、排序
Criteria c = session.createCriteria(Customer.class); c.addOrder(Order.asc("cust_id")); //c.addOrder(Order.desc("cust_id"));
5、统计
Criteria c = session.createCriteria(Customer.class); //设置查询目标 c.setProjection(Projections.rowCount());
离线查询对象
离线查询即不需要Session对象,可以实现动态拼接查询条件。
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class); dc.add(Restrictions.idEq(6l));//拼装条件(全部与普通Criteria一致) //---------------------------------------------------- Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); //---------------------------------------------------- Criteria c = dc.getExecutableCriteria(session); List list = c.list(); System.out.println(list); //---------------------------------------------------- tx.commit(); session.close();
抓取策略
抓取策略是当应用程序需要在关联关系间进行导航的时候,Hibernate如何获取关联对象的策略。
抓取策略是Hibernate提升性能的一种手段,可以在获取关联对象的时候,对发送的语句进行优化,但是往往抓取策略需要和延迟加载一起使用来提升性能。
延迟加载
延迟加载是Hibernate关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。
延迟加载分为两类:类级别延迟 和关联级别的延迟。
类级别延迟
类级别延迟是指查询某个对象的时候,是否采用有延迟,这个通常在<class>标签上配置lazy属性。
get方法:没有任何策略.调用即立即查询数据库加载数据.
load方法: 应用类级别的加载策略-懒加载|延迟加载。所以使用load方法去查询的时候,不会马上发送SQL语句,当真正使用该对象的时候,才会发送SQL语句。
- lazy:true(默认值), 查询类时,会返回代理对象.会在使用属性时,根据关联的session查询数据库.加载数据.
- lazy:false. load方法会与get方法没有任何区别.调用时即加载数据.
示例:
//懒加载|延迟加载 public class Demo { @Test // get方法 : 立即加载.执行方法时立即发送sql语句查询结果 public void fun1(){ Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); //---------------------------------------------------- Customer c = session.get(Customer.class, 2l); System.out.println(c); //---------------------------------------------------- tx.commit(); session.close(); } @Test // load方法(默认):是在执行时,不发送任何sql语句.返回一个对象.使用该对象时,才执行查询. // 延迟加载: 仅仅获得没有使用.不会查询.在使用时才进行查询. // 是否对类进行延迟加载: 可以通过在class元素上配置lazy属性来控制. //lazy:true 加载时,不查询.使用时才查询b //lazy:false 加载时立即查询. public void fun2(){ Session session = HibernateUtils.openSession(); Transaction tx = session.beginTransaction(); //---------------------------------------------------- Customer c = session.load(Customer.class, 2l); //---------------------------------------------------- tx.commit(); session.close(); System.out.println(c); }
<class name="Customer" table="cst_customer" lazy="false" >
类名中凡是有$$的标识符都是代理对象。增强了Customer具有查询数据库的功能。
如果不想使用延迟加载,可以把这个类的映射文件上的lazy设置为false。也可以将这个持久化类改为final修饰。此时无法生成代理类,就会时延迟加载失效。
结论:为了提高效率.建议使用延迟加载(懒加载)
注意:使用懒加载时要确保,调用属性加载数据时,session还是打开的.不然会抛出异常。
关联级别延迟
关联级别延迟是指查询一个对象的关联对象的时候是否采用延迟加载。这个通常在<set>或<many-to-one>上配置lazy属性。
Customer c = session.get(Customer.class, 2l); Set<LinkMan> linkMens = c.getLinkMens();//关联级别
通过客户查询其关联的联系人对象,在查询联系人的时候是否采用延迟加载称为关联级别的延迟。
<set>标签上的lazy通常有三个取值:
- true:默认值,采用延迟加载
- false:检索关联对象的时候,不采用延迟加载
- extra:及其惰性的
<many-to-one>标签上的lazy通常有三个取值:
- proxy:默认值,是否采用延迟加载取决于一的一方上的lazy属性的值。
- false:检索关联对象的时候,不采用延迟加载
- no-proxy:不用研究
抓取策略
抓取策略值得是查询某个对象的时候,如何抓取其关联对象。这个也可以通过配置完成。在关联对象的标签上配置fetch属性。关联上就分为是在<set>和<many-to-one>上,也都有不同的取值。
<set>标签上的fetch通常有三个取值:
- select:默认值,发送的是普通的select语句查询。
- join:发送一条迫切左外链接去查询
- subselect:发送一条子查询语句查询其关联对象。
<many-to-one>标签上的fetch有两个取值:
- select:默认值,发送一条普通的select语句查询关联对象。
- join:发送一条迫切左外链接语句去查询其关联对象。
fetch和lazy组合就会产生很多种的效果。其实不用担心,因为fetch如果设置为join,lazy就会失效了。
演示:
<!-- lazy属性: 决定是否延迟加载 true(默认值): 延迟加载,懒加载 false: 立即加载 extra: 极其懒惰 fetch属性: 决定加载策略.使用什么类型的sql语句加载集合数据 select(默认值): 单表查询加载 join: 使用多表查询加载集合 subselect:使用子查询加载集合 --> <!-- batch-size: 抓取集合的数量为3. 抓取客户的集合时,一次抓取几个客户的联系人集合. --> <set name="linkMens" fecth="" lazy="'> <key column="lkm_cust_id" ></key> <one-to-many class="LinkMan" /> </set>
1、fetch:select,lazy:true的情况
1 //集合级别的关联 2 //fetch:select 单表查询 3 //lazy:true 使用时才加载集合数据. 4 @Test 5 public void fun1(){ 6 Session session = HibernateUtils.openSession(); 7 Transaction tx = session.beginTransaction(); 8 //---------------------------------------------------- 9 Customer c = session.get(Customer.class, 2l); 10 Set<LinkMan> linkMens = c.getLinkMens();//关联级别 11 System.out.println(linkMens); 12 //---------------------------------------------------- 13 tx.commit(); 14 session.close(); 15 16 }
在第9行查询Customer的时候并没有立即查询linkMens,生成sql如下:
select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_linkman as cust_lin6_0_0_, customer0_.cust_phone as cust_pho7_0_0_, customer0_.cust_mobile as cust_mob8_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
在第11行使用linkMens的时候才去数据库查,生成sql如下:
select linkmens0_.lkm_cust_id as lkm_cus10_1_0_, linkmens0_.lkm_id as lkm_id1_1_0_, linkmens0_.lkm_id as lkm_id1_1_1_, linkmens0_.lkm_gender as lkm_gend2_1_1_, linkmens0_.lkm_name as lkm_name3_1_1_, linkmens0_.lkm_phone as lkm_phon4_1_1_, linkmens0_.lkm_email as lkm_emai5_1_1_, linkmens0_.lkm_qq as lkm_qq6_1_1_, linkmens0_.lkm_mobile as lkm_mobi7_1_1_, linkmens0_.lkm_memo as lkm_memo8_1_1_, linkmens0_.lkm_position as lkm_posi9_1_1_, linkmens0_.lkm_cust_id as lkm_cus10_1_1_ from cst_linkman linkmens0_ where linkmens0_.lkm_cust_id=?
2、fetch:select,lazy:false的情况
1 //集合级别的关联 2 //fetch:select 单表查询 3 //lazy:false 立即记载集合数据 4 @Test 5 public void fun2(){ 6 Session session = HibernateUtils.openSession(); 7 Transaction tx = session.beginTransaction(); 8 //---------------------------------------------------- 9 10 Customer c = session.get(Customer.class, 2l); 11 12 Set<LinkMan> linkMens = c.getLinkMens();//关联级别 13 14 System.out.println(linkMens); 15 16 //---------------------------------------------------- 17 tx.commit(); 18 session.close(); 19 20 }
在加载Customer的时候就会把关联的表的数据查询出来,生成sql如下:
select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_linkman as cust_lin6_0_0_, customer0_.cust_phone as cust_pho7_0_0_, customer0_.cust_mobile as cust_mob8_0_0_ from cst_customer customer0_ where customer0_.cust_id=? Hibernate: select linkmens0_.lkm_cust_id as lkm_cus10_1_0_, linkmens0_.lkm_id as lkm_id1_1_0_, linkmens0_.lkm_id as lkm_id1_1_1_, linkmens0_.lkm_gender as lkm_gend2_1_1_, linkmens0_.lkm_name as lkm_name3_1_1_, linkmens0_.lkm_phone as lkm_phon4_1_1_, linkmens0_.lkm_email as lkm_emai5_1_1_, linkmens0_.lkm_qq as lkm_qq6_1_1_, linkmens0_.lkm_mobile as lkm_mobi7_1_1_, linkmens0_.lkm_memo as lkm_memo8_1_1_, linkmens0_.lkm_position as lkm_posi9_1_1_, linkmens0_.lkm_cust_id as lkm_cus10_1_1_ from cst_linkman linkmens0_ where linkmens0_.lkm_cust_id=?
3、fetch:select,lazy:extra的情况
1 //集合级别的关联 2 //fetch:select 单表查询 3 //lazy:extra 极其懒惰.与懒加载效果基本一致. 如果只获得集合的size. //只查询集合的size(count语句) 4 @Test 5 public void fun3(){ 6 Session session = HibernateUtils.openSession(); 7 Transaction tx = session.beginTransaction(); 8 //---------------------------------------------------- 9 10 Customer c = session.get(Customer.class, 2l); 11 12 Set<LinkMan> linkMens = c.getLinkMens();//关联级别 13 14 System.out.println(linkMens.size()); 15 16 System.out.println(linkMens); 17 18 //---------------------------------------------------- 19 tx.commit(); 20 session.close(); 21 22 }
在第10行查询Customer的时候并没有立即查询linkMens,生成sql如下:
Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_linkman as cust_lin6_0_0_, customer0_.cust_phone as cust_pho7_0_0_, customer0_.cust_mobile as cust_mob8_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
在第14行需要使用的时候才查询,而且并没有把linkMens的数据查询出来。生成sql如下:
Hibernate: select count(lkm_id) from cst_linkman where lkm_cust_id =?
4、fetch:join,lazy:true的情况
1 //集合级别的关联 2 //fetch:join 多表查询 3 //lazy:true|false|extra 失效.立即加载. 4 @Test 5 public void fun4(){ 6 Session session = HibernateUtils.openSession(); 7 Transaction tx = session.beginTransaction(); 8 //---------------------------------------------------- 9 10 Customer c = session.get(Customer.class, 1l); 11 12 Set<LinkMan> linkMens = c.getLinkMens();//关联级别 13 14 System.out.println(linkMens.size()); 15 16 System.out.println(linkMens); 17 18 //---------------------------------------------------- 19 tx.commit(); 20 session.close(); 21 22 }
在第10行查询Customer的时候linkMens也一并被查询出来,后面的操作不再生成sql了,生成sql如下:
Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_linkman as cust_lin6_0_0_, customer0_.cust_phone as cust_pho7_0_0_, customer0_.cust_mobile as cust_mob8_0_0_, linkmens1_.lkm_cust_id as lkm_cus10_1_1_, linkmens1_.lkm_id as lkm_id1_1_1_, linkmens1_.lkm_id as lkm_id1_1_2_, linkmens1_.lkm_gender as lkm_gend2_1_2_, linkmens1_.lkm_name as lkm_name3_1_2_, linkmens1_.lkm_phone as lkm_phon4_1_2_, linkmens1_.lkm_email as lkm_emai5_1_2_, linkmens1_.lkm_qq as lkm_qq6_1_2_, linkmens1_.lkm_mobile as lkm_mobi7_1_2_, linkmens1_.lkm_memo as lkm_memo8_1_2_, linkmens1_.lkm_position as lkm_posi9_1_2_, linkmens1_.lkm_cust_id as lkm_cus10_1_2_ from cst_customer customer0_ left outer join cst_linkman linkmens1_ on customer0_.cust_id=linkmens1_.lkm_cust_id where customer0_.cust_id=?
5、fetch:subselect,lazy:true的情况
1 @Test 2 //fetch: subselect 子查询 3 //lazy: true 懒加载 4 public void fun5(){ 5 Session session = HibernateUtils.openSession(); 6 Transaction tx = session.beginTransaction(); 7 //---------------------------------------------------- 8 String hql = "from Customer"; 9 Query query = session.createQuery(hql); 10 List<Customer> list = query.list(); 11 for(Customer c:list){ 12 System.out.println(c); 13 System.out.println(c.getLinkMens().size()); 14 System.out.println(c.getLinkMens()); 15 } 16 //---------------------------------------------------- 17 tx.commit(); 18 session.close(); 19 }
在第10行查询Customer的时候并没有立即查询linkMens,生成sql如下:
Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_name as cust_nam2_0_, customer0_.cust_source as cust_sou3_0_, customer0_.cust_industry as cust_ind4_0_, customer0_.cust_level as cust_lev5_0_, customer0_.cust_linkman as cust_lin6_0_, customer0_.cust_phone as cust_pho7_0_, customer0_.cust_mobile as cust_mob8_0_ from cst_customer customer0_
当执行到第13行时,使用子查询获取linkMens的数据,生成sql如下:
Hibernate: select linkmens0_.lkm_cust_id as lkm_cus10_1_0_, linkmens0_.lkm_id as lkm_id1_1_0_, linkmens0_.lkm_id as lkm_id1_1_1_, linkmens0_.lkm_gender as lkm_gend2_1_1_, linkmens0_.lkm_name as lkm_name3_1_1_, linkmens0_.lkm_phone as lkm_phon4_1_1_, linkmens0_.lkm_email as lkm_emai5_1_1_, linkmens0_.lkm_qq as lkm_qq6_1_1_, linkmens0_.lkm_mobile as lkm_mobi7_1_1_, linkmens0_.lkm_memo as lkm_memo8_1_1_, linkmens0_.lkm_position as lkm_posi9_1_1_, linkmens0_.lkm_cust_id as lkm_cus10_1_1_ from cst_linkman linkmens0_ where linkmens0_.lkm_cust_id=?
6、fetch:subselect,lazy:false的情况
1 @Test 2 //fetch: subselect 子查询 3 //lazy: false 立即加载 4 public void fun6(){ 5 Session session = HibernateUtils.openSession(); 6 Transaction tx = session.beginTransaction(); 7 //---------------------------------------------------- 8 String hql = "from Customer"; 9 Query query = session.createQuery(hql); 10 List<Customer> list = query.list(); 11 for(Customer c:list){ 12 System.out.println(c); 13 System.out.println(c.getLinkMens().size()); 14 System.out.println(c.getLinkMens()); 15 } 16 //---------------------------------------------------- 17 tx.commit(); 18 session.close(); 19 }
执行第10行时,会查询出所有数据,生成sql如下:
Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_name as cust_nam2_0_, customer0_.cust_source as cust_sou3_0_, customer0_.cust_industry as cust_ind4_0_, customer0_.cust_level as cust_lev5_0_, customer0_.cust_linkman as cust_lin6_0_, customer0_.cust_phone as cust_pho7_0_, customer0_.cust_mobile as cust_mob8_0_ from cst_customer customer0_ Hibernate: select linkmens0_.lkm_cust_id as lkm_cus10_1_0_, linkmens0_.lkm_id as lkm_id1_1_0_, linkmens0_.lkm_id as lkm_id1_1_1_, linkmens0_.lkm_gender as lkm_gend2_1_1_, linkmens0_.lkm_name as lkm_name3_1_1_, linkmens0_.lkm_phone as lkm_phon4_1_1_, linkmens0_.lkm_email as lkm_emai5_1_1_, linkmens0_.lkm_qq as lkm_qq6_1_1_, linkmens0_.lkm_mobile as lkm_mobi7_1_1_, linkmens0_.lkm_memo as lkm_memo8_1_1_, linkmens0_.lkm_position as lkm_posi9_1_1_, linkmens0_.lkm_cust_id as lkm_cus10_1_1_ from cst_linkman linkmens0_ where linkmens0_.lkm_cust_id=?
7、fetch:subselect,lazy:extra的情况
1 @Test 2 //fetch: subselect 子查询 3 //lazy: extra 极其懒惰 4 public void fun7(){ 5 Session session = HibernateUtils.openSession(); 6 Transaction tx = session.beginTransaction(); 7 //---------------------------------------------------- 8 String hql = "from Customer"; 9 Query query = session.createQuery(hql); 10 List<Customer> list = query.list(); 11 for(Customer c:list){ 12 System.out.println(c); 13 System.out.println(c.getLinkMens().size()); 14 System.out.println(c.getLinkMens()); 15 } 16 //---------------------------------------------------- 17 tx.commit(); 18 session.close(); 19 20 }
执行第10行时,查询Customer对象,linkMens未查询,生成SQL语句如下:
Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_name as cust_nam2_0_, customer0_.cust_source as cust_sou3_0_, customer0_.cust_industry as cust_ind4_0_, customer0_.cust_level as cust_lev5_0_, customer0_.cust_linkman as cust_lin6_0_, customer0_.cust_phone as cust_pho7_0_, customer0_.cust_mobile as cust_mob8_0_ from cst_customer customer0_
执行到13行时,生成sql语句如下:
Hibernate: select count(lkm_id) from cst_linkman where lkm_cust_id =?
执行到14行时,生成sql语句如下:
Hibernate: select linkmens0_.lkm_cust_id as lkm_cus10_1_0_, linkmens0_.lkm_id as lkm_id1_1_0_, linkmens0_.lkm_id as lkm_id1_1_1_, linkmens0_.lkm_gender as lkm_gend2_1_1_, linkmens0_.lkm_name as lkm_name3_1_1_, linkmens0_.lkm_phone as lkm_phon4_1_1_, linkmens0_.lkm_email as lkm_emai5_1_1_, linkmens0_.lkm_qq as lkm_qq6_1_1_, linkmens0_.lkm_mobile as lkm_mobi7_1_1_, linkmens0_.lkm_memo as lkm_memo8_1_1_, linkmens0_.lkm_position as lkm_posi9_1_1_, linkmens0_.lkm_cust_id as lkm_cus10_1_1_ from cst_linkman linkmens0_ where linkmens0_.lkm_cust_id=?
执行第二次的时候,所有数据都加载好了,就不会再去数据库中查了。
关联属性策略
上面的代码发转过来,获取linkMan,然后加载Customer。
示例:
<!-- fetch 决定加载的sql语句 select: 使用单表查询(默认值) join : 多表查询 lazy 决定加载时机 false: 立即加载 proxy: 由customer的类级别加载策略决定.(默认值) --> <many-to-one name="customer" column="lkm_cust_id" class="Customer" fetch="" lazy="" > </many-to-one>
1、fetch:select,lazy:proxy的情况
1 @Test 2 //fetch:select 单表查询 3 //lazy:proxy 4 //customer-true 懒加载 5 public void fun1(){ 6 Session session = HibernateUtils.openSession(); 7 Transaction tx = session.beginTransaction(); 8 //---------------------------------------------------- 9 10 LinkMan lm = session.get(LinkMan.class, 1l); 11 12 Customer customer = lm.getCustomer(); 13 14 System.out.println(customer); 15 16 //---------------------------------------------------- 17 tx.commit(); 18 session.close(); 19 20 }
执行到第10行时,获取linkman,生成SQL如下:
Hibernate: select linkman0_.lkm_id as lkm_id1_1_0_, linkman0_.lkm_gender as lkm_gend2_1_0_, linkman0_.lkm_name as lkm_name3_1_0_, linkman0_.lkm_phone as lkm_phon4_1_0_, linkman0_.lkm_email as lkm_emai5_1_0_, linkman0_.lkm_qq as lkm_qq6_1_0_, linkman0_.lkm_mobile as lkm_mobi7_1_0_, linkman0_.lkm_memo as lkm_memo8_1_0_, linkman0_.lkm_position as lkm_posi9_1_0_, linkman0_.lkm_cust_id as lkm_cus10_1_0_ from cst_linkman linkman0_ where linkman0_.lkm_id=?
由于Customer类上未做配置,所有默认使用延迟加载。当执行到12行时,生成SQL如下:
Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_linkman as cust_lin6_0_0_, customer0_.cust_phone as cust_pho7_0_0_, customer0_.cust_mobile as cust_mob8_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
2、fetch:select,lazy:proxy,Customer上配置lazy="false"的情况
还是以上代码,但是在Customer的Class配置上加入lazy="false",再次执行。当执行到10行时,生成SQL如下:
Hibernate: select linkman0_.lkm_id as lkm_id1_1_0_, linkman0_.lkm_gender as lkm_gend2_1_0_, linkman0_.lkm_name as lkm_name3_1_0_, linkman0_.lkm_phone as lkm_phon4_1_0_, linkman0_.lkm_email as lkm_emai5_1_0_, linkman0_.lkm_qq as lkm_qq6_1_0_, linkman0_.lkm_mobile as lkm_mobi7_1_0_, linkman0_.lkm_memo as lkm_memo8_1_0_, linkman0_.lkm_position as lkm_posi9_1_0_, linkman0_.lkm_cust_id as lkm_cus10_1_0_ from cst_linkman linkman0_ where linkman0_.lkm_id=? Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_linkman as cust_lin6_0_0_, customer0_.cust_phone as cust_pho7_0_0_, customer0_.cust_mobile as cust_mob8_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
3、fetch:select,lazy:false的情况,同上面2的情况一样。
4、fetch:join,lazy:proxy的情况
1 @Test 2 //fetch:join 多表 3 //lazy: 失效 4 public void fun3(){ 5 Session session = HibernateUtils.openSession(); 6 Transaction tx = session.beginTransaction(); 7 //---------------------------------------------------- 8 LinkMan lm = session.get(LinkMan.class, 3l); 9 Customer customer = lm.getCustomer(); 10 System.out.println(customer); 11 //---------------------------------------------------- 12 tx.commit(); 13 session.close(); 14 15 }
当执行到第8行时,生成SQL语句如下:
Hibernate: select linkman0_.lkm_id as lkm_id1_1_0_, linkman0_.lkm_gender as lkm_gend2_1_0_, linkman0_.lkm_name as lkm_name3_1_0_, linkman0_.lkm_phone as lkm_phon4_1_0_, linkman0_.lkm_email as lkm_emai5_1_0_, linkman0_.lkm_qq as lkm_qq6_1_0_, linkman0_.lkm_mobile as lkm_mobi7_1_0_, linkman0_.lkm_memo as lkm_memo8_1_0_, linkman0_.lkm_position as lkm_posi9_1_0_, linkman0_.lkm_cust_id as lkm_cus10_1_0_, customer1_.cust_id as cust_id1_0_1_, customer1_.cust_name as cust_nam2_0_1_, customer1_.cust_source as cust_sou3_0_1_, customer1_.cust_industry as cust_ind4_0_1_, customer1_.cust_level as cust_lev5_0_1_, customer1_.cust_linkman as cust_lin6_0_1_, customer1_.cust_phone as cust_pho7_0_1_, customer1_.cust_mobile as cust_mob8_0_1_ from cst_linkman linkman0_ left outer join cst_customer customer1_ on linkman0_.lkm_cust_id=customer1_.cust_id where linkman0_.lkm_id=?
结论:为了提高效率,fetch的选择上应选select,lazy选择true。所以全部使用默认值。
no-session问题
延迟加载的问题是指当我们调用完action中的某个方法,在jsp页面要显示我们想要的信息的时候,发现在dao中打开的session已经关闭了。
解决方式:扩大session的作用范围。可以在过滤器中放行之前打开session,放行之后关闭session。
批量抓取
在抓取的策略中有一种叫做批量抓取,就是同时查询多个对象的关联对象时,可以采用批量抓取进行优化。当然这个就不是特别重要了。通过配置batch-size来完成。
示例:
1 @Test 2 public void fun10(){ 3 Session session = HibernateUtils.openSession(); 4 Transaction tx = session.beginTransaction(); 5 //---------------------------------------------------- 6 7 String hql = "from Customer "; 8 Query query = session.createQuery(hql); 9 List<Customer> list = query.list(); 10 11 for(Customer c:list){ 12 System.out.println(c.getLinkMens()); 13 } 14 15 //---------------------------------------------------- 16 tx.commit(); 17 session.close(); 18 }
在没有配置批量抓取之前,每次执行到第12行时,就会生成SQL语句去数据库查,循环几次,就要查询几次。
进行批量抓取配置之后,重新执行上面代码:
<!-- batch-size: 抓取集合的数量为3. 抓取客户的集合时,一次抓取几个客户的联系人集合. --> <set name="linkMens" batch-size="3" > <key column="lkm_cust_id" ></key> <one-to-many class="LinkMan" /> </set>
生成SQL语句如下:
Hibernate: select linkmens0_.lkm_cust_id as lkm_cus10_1_1_, linkmens0_.lkm_id as lkm_id1_1_1_, linkmens0_.lkm_id as lkm_id1_1_0_, linkmens0_.lkm_gender as lkm_gend2_1_0_, linkmens0_.lkm_name as lkm_name3_1_0_, linkmens0_.lkm_phone as lkm_phon4_1_0_, linkmens0_.lkm_email as lkm_emai5_1_0_, linkmens0_.lkm_qq as lkm_qq6_1_0_, linkmens0_.lkm_mobile as lkm_mobi7_1_0_, linkmens0_.lkm_memo as lkm_memo8_1_0_, linkmens0_.lkm_position as lkm_posi9_1_0_, linkmens0_.lkm_cust_id as lkm_cus10_1_0_ from cst_linkman linkmens0_ where linkmens0_.lkm_cust_id in ( ?, ?, ? )
此时一次会拿3条数据,而不会每次都到数据库中查了。