十一、Hibernate的检索策略
1、概述:
查询的时机:什么时候去查?
1 /** 2 * 一张表的检索策略我们称之为: 3 * 类级别的检索策略。 4 * 注意:只要是说类级别的检索策略,就一定不涉及关联对象。 5 * 6 * 类级别检索策略解决的问题: 7 * 1、查询的时机: 8 * 分为两种情况 9 * 立即加载:不管用不用,都马上查询出来 10 * 延迟加载:什么时候用,什么时候去查询。(懒加载,惰性加载) 11 12 * 13 *常用方法: 14 * get: 15 * 永远都是立即加载。返回的当前实体类的对象。 16 * load 17 * 默认情况下是延迟加载。返回的当前实体类的代理对象。 18 * 它可以改为立即加载。 19 * 在对应的映射文件中,class元素使用lazy属性,把值改为false 20 * lazy取值:true 延迟加载(默认值)。false是立即加载。 21 * 例如: 22 * <class name="Customer" table="T_CUSTOMERS" lazy="false"> 23 * query的list方法: 24 * 永远都是立即加载。 25 * 26 * @author zhy 27 * 28 */ 29 public class HibernateDemo1 { 30 31 /* 32 * 不管用不用,都立即查询出一个客户的所有字段数据 33 */ 34 @Test 35 public void test1(){ 36 Session s = HibernateUtil.getSession(); 37 Transaction tx = s.beginTransaction(); 38 //查询id为1的客户 39 Customer c1 = s.get(Customer.class, 1); 40 System.out.println(c1); 41 tx.commit(); 42 s.close(); 43 44 } 45 /* 46 * 什么时候用什么时候真正去查询 47 */ 48 @Test 49 public void test2(){ 50 Session s = HibernateUtil.getSession(); 51 Transaction tx = s.beginTransaction(); 52 //查询id为1的客户 53 Customer c1 = s.load(Customer.class, 1); 54 System.out.println(c1); 55 tx.commit(); 56 s.close(); 57 58 } 59 }
2、类级别的检索策略
只影响Session的load()方法
Session.get()方法:永远都是立即加载。
1 /* 2 * 不管用不用,都立即查询出一个客户的所有字段数据 3 */ 4 @Test 5 public void test1(){ 6 Session s = HibernateUtil.getSession(); 7 Transaction tx = s.beginTransaction(); 8 //查询id为1的客户 9 Customer c1 = s.get(Customer.class, 1); 10 System.out.println(c1); 11 tx.commit(); 12 s.close(); 13 14 }
Query.list()方法:立即检索。
Session.load()方法:默认是延迟加载。(load可以改为立即加载,lazy="false")
1 @Test 2 public void test2(){ 3 Session s = HibernateUtil.getSession(); 4 Transaction tx = s.beginTransaction(); 5 //查询所有客户 6 Query query = s.createQuery("from Customer"); 7 List<Customer> cs = query.list(); 8 //获取每个客户的所有订单 9 for(Customer c : cs){ 10 System.out.println(c); 11 System.out.println(c.getOrders()); 12 } 13 tx.commit(); 14 s.close(); 15 }
1 /* 2 * 什么时候用什么时候真正去查询 3 */ 4 @Test 5 public void test2(){ 6 Session s = HibernateUtil.getSession(); 7 Transaction tx = s.beginTransaction(); 8 //查询id为1的客户 9 Customer c1 = s.load(Customer.class, 1); 10 System.out.println(c1); 11 tx.commit(); 12 s.close(); 13 14 }
3、关联级别的检索策略
概念:比如查询客户(类级别),所关联的订单的查询(关联级别)。
3.1、检索关联多的一方
应用场景:
一对多:根据客户查询订单
多对多:根据老师查询学生
配置:
1 <hibernate-mapping package="cn.itcast.domain"> 2 <class name="Customer" table="T_CUSTOMERS"> 3 <id name="id" column="id"> 4 <generator class="native"></generator> 5 </id> 6 <property name="name" column="NAME"></property> 7 <property name="age" column="AGE"></property> 8 <!-- 一对多关系映射: 9 set元素: 10 作用:映射集合元素 11 属性: 12 name:映射实体类中的集合属性 13 table:指定对应的表 14 key元素:它是set的子元素 15 作用:就是用于指定外键的 16 属性: 17 column:指定外键字段的名称 18 one-to-many元素:它是set的子元素 19 作用:描述当前实体映射文件和set中指定属性之间的关系。 20 属性: 21 class:指定是从表的实体类名称 22 --> 23 <set name="orders" table="T_ORDERS" lazy="true" fetch="join"> 24 <key column="CUSTOMER_ID"></key> 25 <one-to-many class="Order"/> 26 </set> 27 </class> 28 </hibernate-mapping>
lazy:查询的时机(何时真正去查)。取值如下:
true:延迟加载
false:立即加载
fetch:查询的语句的形式。取值如下:
select:多条查询语句。
subselect:子查询。推荐
join:左外连接查询
说明:(必须搞明白)
序号 |
lazy的取值 |
fetch的取值 |
说明(都是以客户订单的一对多关系为例) |
1 |
true(默认值) |
select(默认值) |
时机:用时才真正去查询订单。 语句形式:有1条查询客户的和多条查询订单的select语句。 Batch-size:设置批量检索的深度。(建议3~10之间) |
2 |
false |
select(默认值) |
时机:不管用不用订单,查询客户时都立即查询订单。 语句形式:有1条查询客户的和多条查询订单的select语句。 Batch-size:设置批量检索的深度。(建议3~10之间) |
3 |
extra |
select(默认值) |
时机:用什么信息,查什么信息。只查询必要的。 语句形式:有1条查询客户的和多条查询订单的select语句。 batch-size:设置批量检索的深度。(建议3~10之间) |
4 |
true |
subselect |
时机:用时才真正去查询订单。 语句形式:子查询 batch-size:无效 |
5 |
false |
subselect |
时机:不管用不用订单,查询客户时都立即查询订单。 语句形式:子查询 batch-size:无效 |
6 |
extra |
subselect |
时机:用什么信息,查什么信息。只查询必要的。 语句形式:子查询 batch-size:无效 |
7 |
true|false|extra |
join(当join有效时,根本不看lazy属性) |
时机:无效。因为连接查询,一次就是两张表及以上。 语句:left outer join batch-size:无效 注意:Query查询会忽略join的存在。当join无效时,lazy就有效了。 |
1 /** 2 * 关联级别的检索策略 3 * 注意: 4 * 它永远说的是查询当前实体类时,要不要查询那个关联的对象。 5 * 涉及的是:一对多,多对一,多对多和一对一。 6 * 举例: 7 * 一对多和多对一 8 * 查询客户的时候要不要查询订单:一对多的情况 9 * 查询订单的时候要不要查询客户:多对一的情况 10 * 多对多 11 * 查询教师的时候要不要查询学生:多对多的情况 12 * 一对一 13 * 查询人员的时候要不要查询身份证号:一对一的情况 14 * 15 * 解决的问题: 16 * 1、查询的时机 17 * 立即加载:不管用不用,都马上查询出来 18 * 延迟加载:什么时候用,什么时候真正去查询 19 * 2、查询的方式(怎么查) 20 * 多条SQL语句 21 * 子查询 22 * 表连接 23 * 关于关联级别的检索策略,有如下配置 24 * 明确:是有少的一方,根据少的一方,去检索多的一方 25 * 举例说明: 26 * 我们有客户,根据客户获取订单。/ 我们有一个教师,根据这个教师获取学生 27 * 配置涉及的属性: 28 * lazy:加载的时机 29 * true:延迟加载(默认值) 30 * false:立即加载 31 * extra:极懒加载 (用什么查什么,不用的都不查) 32 * fetch:检索的方式 33 * select:多条SQL语句(默认值) 34 * subselect:子查询 35 * join:左外连接 36 * 37 * 我们现在是在映射文件的set元素上配置! 38 * 39 * @author zhy 40 * 41 * 第四种情况:lazy="true" fetch="subselect" 42 * <set name="orders" table="T_ORDERS" lazy="true" fetch="subselect"> 43 * 44 */ 45 public class HibernateDemo5 { 46 47 /* 48 * 需求: 49 * 查询所有客户,获取每个客户的所有订单 50 * 查询的时机: 51 * 延迟加载 52 * 查询的方式: 53 * 子查询 54 * select * from T_ORDERS where CUSTOMER_ID in (select id from T_CUSTOMERS ) 55 * 注意: 56 * 当使用了子查询之后,batch-size属性就失效了。 57 * 58 */ 59 @Test 60 public void test2(){ 61 Session s = HibernateUtil.getSession(); 62 Transaction tx = s.beginTransaction(); 63 //查询所有客户 64 Query query = s.createQuery("from Customer"); 65 List<Customer> cs = query.list(); 66 //获取每个客户的所有订单 67 for(Customer c : cs){ 68 System.out.println(c); 69 System.out.println(c.getOrders()); 70 } 71 tx.commit(); 72 s.close(); 73 } 74 75 76 /*当我们的fetch属性是subselect时,查询一个客户,并且获取该客户的订单,和取默认值没有区别。 77 * 因为: 78 * select * from t_orders where customer_id = 1; 79 select * from t_orders where customer_id in (1); 80 是一回事。 81 * 82 * 83 * 需求: 84 * 查询一个客户,获取该客户的所有订单 85 * 查询的时机: 86 * 查询的方式: 87 */ 88 @Test 89 public void test1(){ 90 Session s = HibernateUtil.getSession(); 91 Transaction tx = s.beginTransaction(); 92 //查询一个客户 93 Customer c1 = s.get(Customer.class, 1);//客户说的是类级别的检索策略 94 System.out.println(c1); 95 //获取当前客户的所有订单 96 System.out.println(c1.getOrders()); 97 tx.commit(); 98 s.close(); 99 } 100 }
1 /** 2 * 关联级别的检索策略 3 * 注意: 4 * 它永远说的是查询当前实体类时,要不要查询那个关联的对象。 5 * 涉及的是:一对多,多对一,多对多和一对一。 6 * 举例: 7 * 一对多和多对一 8 * 查询客户的时候要不要查询订单:一对多的情况 9 * 查询订单的时候要不要查询客户:多对一的情况 10 * 多对多 11 * 查询教师的时候要不要查询学生:多对多的情况 12 * 一对一 13 * 查询人员的时候要不要查询身份证号:一对一的情况 14 * 15 * 明确: 有多的一方要不要查询少的一方 16 * 举例说明: 17 * 有订单,要不要查询客户/有人员,要不要查询身份证号。 18 * 解决的问题: 19 * 1、查询的时机 20 * 立即加载:不管用不用,都马上查询出来 21 * 延迟加载:什么时候用,什么时候真正去查询 22 * 2、查询的方式(怎么查) 23 * 多条SQL语句 24 * 表连接 25 * 关于关联级别的检索策略,有如下配置 26 * 配置涉及的属性: 27 * lazy:加载的时机 28 * false:立即加载。不管对方类级别的检索策略 29 * proxy:不确定。原因是要看对方类级别的检索策略。 30 * 如果对方类级别检索策略是延迟加载,则proxy就是延迟加载。 31 * 如果对方类级别检索策略是立即记载,则proxy就是立即加载。 32 * fetch:检索的方式 33 * select:多条SQL语句 34 * join:左外连接 35 * 36 * 我们以多对一为例:配置都是在many-to-one上! 37 * @author zhy 38 * 39 * 第二种情况:lazy=proxy fetch=join 40 * <many-to-one name="customer" class="Customer" column="CUSTOMER_ID" lazy="proxy" fetch="join"/> 41 * 42 */ 43 public class HibernateDemo11 { 44 45 46 /* 当fetch取值是join时,一下就查询2张表。就不管lazy属性如何配置。 47 * 48 * 需求: 49 * 查询一个订单,根据订单获取该订单的客户 50 * 查询的时机: 51 * lazy属性失效 52 * 查询的方式: 53 * 左外连接 54 * 55 */ 56 @Test 57 public void test1(){ 58 Session s = HibernateUtil.getSession(); 59 Transaction tx = s.beginTransaction(); 60 //查询订单 61 Order o1 = s.get(Order.class, 1); 62 System.out.println(o1); 63 //根据订单,获取客户信息 64 System.out.println(o1.getCustomer()); 65 tx.commit(); 66 s.close(); 67 } 68 }
3.2、检索关联少的一方
应用场景:(开发经验,少的一方,查出来就得了)
多对一:根据订单查询客户
一对一:根据人查询身份证
配置:
1 <hibernate-mapping package="cn.itcast.domain"> 2 <class name="Order" table="T_ORDERS"> 3 <id name="id" column="id"> 4 <generator class="native"></generator> 5 </id> 6 <property name="ordernum" column="ORDERNUM"></property> 7 <property name="money" column="MONEY"></property> 8 9 <!-- 多对一关系映射 10 使用的元素:many-to-one 11 属性: 12 name:指定的是在实体类中要映射的属性 13 class:指定该属性所对应的类 14 column:指定外键字段。 15 --> 16 <many-to-one name="customer" class="Customer" column="CUSTOMER_ID" lazy="proxy" fetch="join"/> 17 </class> 18 </hibernate-mapping>
十二、检索方式
1、检索方式概述
a) 对象导航方式:通过对象间的引用关系。例如:customer.getOrder();
b) OID的检索方式:通过OID获取对象get和load。
c) HQL检索方式:使用面向对象的HQL查询语言。
HQL:Hibernate Query Language 类似SQL。表明换类名
d) QBC检索方式:Query By Criteria,更加面向对象。了解。
e) 本地SQL检索方式:原生态的JDBC+SQL语句。了解。
2、单表各种查询(HQL条件,QBC条件,QBC特例,原始SQL,多态,排序,具名,命名,分页)
1 /** 2 * hibernate中提供的查询方式 3 * @author zhy 4 * 5 */ 6 public class HibernateDemo1 { 7 8 /* 9 * 对象导航查询 10 * 11 * 明确: 12 * 思想的转变。我们在需要某些数据时,是否还要单独去写一个方法来实现。 13 * 14 * 对象导航的思想 15 */ 16 @Test 17 public void test17(){ 18 Session s = HibernateUtil.getSession(); 19 Transaction tx = s.beginTransaction(); 20 Order o1 = s.get(Order.class, 1); 21 Customer c = o1.getCustomer();//对象导航的方式 22 System.out.println(c); 23 tx.commit(); 24 s.close(); 25 } 26 @Test 27 public void test15(){ 28 Session s = HibernateUtil.getSession(); 29 Transaction tx = s.beginTransaction(); 30 Customer c1 = s.get(Customer.class, 1); 31 Set<Order> orders = c1.getOrders();//对象导航的方式 32 System.out.println(orders); 33 tx.commit(); 34 s.close(); 35 } 36 /*原来JDBC时,留下的思想 37 @Test 38 public void test16(){ 39 List<Order> orders = findOrderByCustomerid(1); 40 System.out.println(orders); 41 } 42 43 public List<Order> findOrderByCustomerid(int customerid){ 44 Session s = HibernateUtil.getSession(); 45 Transaction tx = s.beginTransaction(); 46 //select * from t_orders where customer_id = ?; 47 Query query = s.createQuery("from Order o where o.customer.id = ?"); 48 query.setInteger(0, customerid); 49 List<Order> orders = query.list(); 50 tx.commit(); 51 s.close(); 52 return orders; 53 } 54 */ 55 56 /* 57 * 原生SQL查询 58 * 使用的是session的createSQLQuery方法 59 * 它的执行list结果是一个由Object数组组成的集合。 60 * 61 * 在实际开发中,我们一般不会使用Object数组来操作。 62 * 而是在执行list()方法之前,调用addEntity方法,给sqlquery添加一个实体, 63 * 从而得到的就是实体对象的集合 64 65 select 66 sum( 67 case when score between 0 and 59 then 1 else 0 end 68 ) as E, 69 sum( 70 case when score between 60 and 69 then 1 else 0 end 71 ) as D, 72 sum( 73 case when score between 70 and 79 then 1 else 0 end 74 ) as C, 75 sum( 76 case when score between 80 and 89 then 1 else 0 end 77 ) as B, 78 sum( 79 case when score between 90 and 99 then 1 else 0 end 80 ) as A 81 from t_students 82 83 */ 84 @Test 85 public void test14(){ 86 Session s = HibernateUtil.getSession(); 87 Transaction tx = s.beginTransaction(); 88 SQLQuery sqlquery = s.createSQLQuery("select * from t_customers");//参数就是SQL语句 89 //给SQLQuery添加一个实体 90 sqlquery.addEntity(Customer.class); 91 List list = sqlquery.list(); 92 tx.commit(); 93 s.close(); 94 for(Object o : list){ 95 System.out.println(o); 96 } 97 98 } 99 /* 100 * 分页查询 101 * mysql中的分页查询: 102 * 使用的关键字:limit 103 * 关键字中的必要条件:firstResult(开始记录索引),maxResults(最大的结果集数) 104 * sql语句:select * from t_orders limit firstResult,maxResults; 105 * 106 * HQL语句:from Order 107 * 108 * 在hibernate中分页只有 109 * setFirstResult 110 * setMaxResults 111 * 不管使用什么数据库都是这两个方法 112 */ 113 @Test 114 public void test9(){ 115 List<Order> orders = findAllOrder(4,2); 116 for(Order o : orders){ 117 System.out.println(o); 118 } 119 } 120 //QBC 121 public List<Order> findAllOrder2(int firstResult,int maxResults){ 122 Session s = HibernateUtil.getSession(); 123 Transaction tx = s.beginTransaction(); 124 Criteria criteria = s.createCriteria(Order.class); 125 criteria.setFirstResult(firstResult);//开始记录的索引 126 criteria.setMaxResults(maxResults);//每页要查询的条数 127 List<Order> list = criteria.list(); 128 tx.commit(); 129 s.close(); 130 return list; 131 } 132 //HQL 133 public List<Order> findAllOrder(int firstResult,int maxResults){ 134 Session s = HibernateUtil.getSession(); 135 Transaction tx = s.beginTransaction(); 136 Query query = s.createQuery("from Order");//select * from t_orders 137 //hibernate提供的方法: 138 query.setFirstResult(firstResult);//开始记录的索引 139 query.setMaxResults(maxResults);//每页要查询的条数 140 List<Order> orders = query.list(); 141 tx.commit(); 142 s.close(); 143 return orders; 144 } 145 /* 146 * 命名查询 147 * 把sql或者HQL在映射文件中配置起来。提供一个名称。 148 * 名称和语句之间是键值对的对应关系。 149 * 在程序使用根据名称获取语句的方法,叫做命名查询 150 */ 151 @Test 152 public void test8(){ 153 Session s = HibernateUtil.getSession(); 154 Transaction tx = s.beginTransaction(); 155 Query query = s.getNamedQuery("findCustomerByCondition"); 156 //给条件赋值 157 query.setString("name", "testD"); 158 query.setInteger("age", 28); 159 List list = query.list(); 160 tx.commit(); 161 s.close(); 162 for(Object o : list){ 163 System.out.println(o); 164 } 165 } 166 /* 167 * 具名查询 168 * 具名其实就是给查询的参数占位符提供一个名称,使我们在查询时,使用名称而不是索引来给参数赋值 169 * 书写规范: 170 * 必须用 :名称 171 */ 172 @Test 173 public void test7(){ 174 Session s = HibernateUtil.getSession(); 175 Transaction tx = s.beginTransaction(); 176 Query query = s.createQuery("from Customer where age > :age and name=:name"); 177 //给条件赋值 178 query.setString("name", "testD"); 179 query.setInteger("age", 28); 180 List list = query.list(); 181 tx.commit(); 182 s.close(); 183 for(Object o : list){ 184 System.out.println(o); 185 } 186 } 187 //多态查询:了解一下 188 @Test 189 public void test6(){ 190 Session s = HibernateUtil.getSession(); 191 Transaction tx = s.beginTransaction(); 192 Query query = s.createQuery("from java.io.Serializable "); 193 List list = query.list(); 194 tx.commit(); 195 s.close(); 196 for(Object o : list){ 197 System.out.println(o); 198 } 199 } 200 /* 201 * 排序查询 202 * 关键字和SQL是一样的。 203 * order by 204 * asc 205 * desc 206 */ 207 @Test 208 public void test5(){ 209 Session s = HibernateUtil.getSession(); 210 Transaction tx = s.beginTransaction(); 211 Query query = s.createQuery("from Customer order by age desc "); 212 List list = query.list(); 213 tx.commit(); 214 s.close(); 215 for(Object o : list){ 216 System.out.println(o); 217 } 218 } 219 /* 220 * QBC特例查询 221 * 特例: 222 * 用实体对象创建一个例子,查询语句的条件就会根据实体对象中提供的例子进行条件的拼装。 223 * 注意: 224 * 1、条件只会用等于 225 * 2、在拼装条件时,它只涉及不为null的字段,同时不会把OID作为条件。 226 */ 227 @Test 228 public void test4(){ 229 //我的例子 230 Customer c = new Customer(); 231 c.setAge(28); 232 c.setName("testA"); 233 Session s = HibernateUtil.getSession(); 234 Transaction tx = s.beginTransaction(); 235 //创建查询对象。参数是要查询的实体 236 Criteria criteria = s.createCriteria(Customer.class); 237 //添加条件 238 criteria.add(Example.create(c));//select * from t_customes where age = 28 239 240 List list = criteria.list(); 241 tx.commit(); 242 s.close(); 243 for(Object o : list){ 244 System.out.println(o); 245 } 246 } 247 //QBC带条件查询 248 @Test 249 public void test3(){ 250 Session s = HibernateUtil.getSession(); 251 Transaction tx = s.beginTransaction(); 252 //创建查询对象。参数是要查询的实体 253 Criteria criteria = s.createCriteria(Customer.class); 254 //添加条件 255 criteria.add(Restrictions.gt("age", 28)); 256 257 List list = criteria.list(); 258 tx.commit(); 259 s.close(); 260 for(Object o : list){ 261 System.out.println(o); 262 } 263 } 264 /* 265 * QBC查询 266 * QBC:query by criteria 267 * QBC能实现的HQL都能实现。反之亦然。 268 * 它更加面向对象 269 */ 270 @Test 271 public void test2(){ 272 Session s = HibernateUtil.getSession(); 273 Transaction tx = s.beginTransaction(); 274 //创建查询对象。参数是要查询的实体 275 Criteria criteria = s.createCriteria(Customer.class); 276 List list = criteria.list(); 277 tx.commit(); 278 s.close(); 279 for(Object o : list){ 280 System.out.println(o); 281 } 282 } 283 /* 284 * HQL带条件查询 285 * hiberante中HQL使用条件,也是where关键字。 286 * 条件的参数占位符也是用的问号 287 * 注意事项: 288 * hibernate中查询语句的参数占位符索引是从0开始的。 289 */ 290 @Test 291 public void test1(){ 292 Session s = HibernateUtil.getSession(); 293 Transaction tx = s.beginTransaction(); 294 Query query = s.createQuery("from Customer where age > ?"); 295 //给条件赋值 296 query.setInteger(0, 28); 297 List list = query.list(); 298 tx.commit(); 299 s.close(); 300 for(Object o : list){ 301 System.out.println(o); 302 } 303 } 304 }
3、多表查询
3.1、交叉连接(cross join)
显示交叉连接:
select t1.*, t2.* from tabel1 t1 cross join table t2
隐式交叉连接:
select t1.*, t2.* from tabel1 t1, table t2
返回结果:两张表的笛卡尔积
3.2、内连接(inner join)
显示内连接:SQL写法
select * from tabel1 t1 inner join table t2 on t1.primary_key = t2.foregin_key
隐式内连接:SQL写法
select * from tabel1 t1, table t2where t1.primary_key = t2.foregin_key
返回结果:是在笛卡尔积的基础上,返回符合条件的结果。
HQL写法:select * from Customer t1 inner join c.orders;
HQL写法:select * from Customer t1 inner join fetch c.orders;
返回结果:
inner join:Object[]
inner join fetch:实体对象
3.3、外连接(outer join 左外和右外其实是一样的)
左外连接: left outer join
select * from customers c left outer join orders o on c.id=o.customer_id;
返回结果:除了满足条件的记录外,左外连接还会返回左表剩余记录。
右外连接: right outer join
select * from customers c right outer join orders o on c.id=o.customer_id;
返回结果:除了满足条件的记录外,右外连接还会返回右表剩余记录。
HQL写法:select * from Customer t1 inner join c.orders;
HQL写法:select * from Customer t1 inner join fetch c.orders;
返回结果:
inner join:Object[]
inner join fetch:实体对象
全外连接:(MySQL不支持) full outer join。返回结果了解一下:除了满足条件的之外,还会返回左表和右表不满足条件的记录。
1 /* 2 * 迫切左外连接查询 3 * 4 * 返回的是一个集合,集合中的每个元素都是左表实体对象。 5 * 有可能重复。重复的原因是看迫切左外连接查询的条件。 6 */ 7 @Test 8 public void test11(){ 9 Session s = HibernateUtil.getSession(); 10 Transaction tx = s.beginTransaction(); 11 Query query = s.createQuery("from Customer c left outer join fetch c.orders "); 12 List list = query.list(); 13 tx.commit(); 14 s.close(); 15 for(Object o : list){ 16 System.out.println(o); 17 } 18 } 19 20 /* 21 * 左外连接查询 22 * 23 * 返回值是一个集合,集合的每个元素是Object数组。 24 * 数组中包含2个Object对象。 25 * 其中一个左表对象和一个右表对象。 26 * 左表对象有可能重复,右表对象不会重复 27 */ 28 @Test 29 public void test10(){ 30 Session s = HibernateUtil.getSession(); 31 Transaction tx = s.beginTransaction(); 32 Query query = s.createQuery("from Customer c left outer join c.orders "); 33 List<Object[]> list = query.list(); 34 tx.commit(); 35 s.close(); 36 for(Object[] os : list){ 37 System.out.println("----------------------"); 38 for(Object o : os){ 39 System.out.println(o); 40 } 41 } 42 }
3.4、投影查询
1 /* 2 * 投影查询 3 * 就想实现 4 * 查询客户时,只有客户的id和name 5 * 查询订单时,只有订单id和money 6 * 投影查询就是: 7 * 在实际开发中,我们只需要一个实体类中的某个或者某些字段,当查询完成后还想使用该实体对象来操作。 8 * 需要把查询的某个或某些字段投射到实体类上,这种查询方式叫投影查询。 9 * 在使用投影查询时的要求: 10 * 实体类必须提供对应参数列表的构造函数。 11 * 在写HQL语句时,需要使用new关键字 12 * 13 * 注意事项: 14 * 在使用投影查询时,如果直接写类名,需要确定该类在工程中唯一。 15 * 如果不唯一的话,需要些类全名。包名.类名 16 */ 17 @Test 18 public void test13(){ 19 Session s = HibernateUtil.getSession(); 20 Transaction tx = s.beginTransaction(); 21 Query query = s.createQuery("select new cn.itcast.domain.Order(o.id,o.money) from Order o"); 22 List list = query.list(); 23 tx.commit(); 24 s.close(); 25 for(Object o : list){ 26 System.out.println(o); 27 } 28 } 29 @Test 30 public void test12(){ 31 Session s = HibernateUtil.getSession(); 32 Transaction tx = s.beginTransaction(); 33 Query query = s.createQuery("select new Customer(c.id,c.name) from Customer c"); 34 List list = query.list(); 35 tx.commit(); 36 s.close(); 37 for(Object o : list){ 38 System.out.println(o); 39 } 40 }
三、附录:QBC自定义条件
短语 |
含义 |
Restrictions.eq |
等于= |
Restrictions.allEq |
使用Map,使用key/value进行多个等于的判断 |
Restrictions.gt |
大于> |
Restrictions.ge |
大于等于>= |
Restrictions.lt |
小于< |
Restrictions.le |
小于等于<= |
Restrictions.between |
对应sql的between子句 |
Restrictions.like |
对应sql的like子句 |
Restrictions.in |
对应sql的in子句 |
Restrictions.and |
and 关系 |
Restrictions.or |
or关系 |
Restrictions.sqlRestriction |
Sql限定查询 |
Restrictions.asc() |
根据传入的字段进行升序排序 |
Restrictions.desc() |
根据传入的字段进行降序排序 |
运算类型 |
HQL运算符 |
QBC运算方法 |
比较运算 |
= |
Restrictions.eq() |
<> |
Restrictions.not(Restrictions.eq()) |
|
>= |
Restrictions.ge() |
|
< |
Restrictions.lt() |
|
<= |
Restrictions.le() |
|
is null |
Restrictions.isNull() |
|
is not null |
Restrictions.isNotNull() |
|
范围运算符 |
in |
Restrictions.in() |
not in |
Restrictions.not(Restrictions.in()) |
|
between |
Restrictions.between() |
|
not between |
Restrictions.not(Restrictions.between()) |
运算类型 |
HQL运算符 |
QBC运算方法 |
字符串模式匹配 |
like |
Restrictions.like() |
逻辑 |
and |
Restrictions.and()| Restrictions.conjunction() |
or |
Restrictions.or()| Restrictions.disjunction() |
|
not |
Restrictions.not() |
|