Hibernate查询以及优化策略04
Posted Sue
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate查询以及优化策略04相关的知识,希望对你有一定的参考价值。
一. HQL查询
1. HQL(hibernate query language)单表查询
1.1 准备项目
-
创建项目: hinernate-03-query
-
引入jar,同前一个项目
-
复制实体(订单,客户),映射,配置,工具类.
1.2 HQL单表基本查询
1 /** 2 * 演示HQL的查询(单表查询) 3 * 1)全表查询 4 * 2)别名查询 5 * 3)条件查询 6 * 4)具名查询 7 * 5)分页查询 8 * 6)查询排序 9 * 7)聚合查询 10 * 8)投影查询 11 */ 12 public class HQLTest1 { 13 /** 14 * 全表查询 15 */ 16 @Test 17 public void test1(){ 18 Session session = HibernateUtil.openSession(); 19 Transaction tx = session.beginTransaction(); 20 21 //注意: 22 //1、不能写 select * from Order 23 //2、Order是对象名,不是表名 24 Query<Order> query = session.createQuery("from Order", Order.class); 25 List<Order> list = query.list(); 26 for (Order order : list) { 27 //为了避免空指针和内存溢出,toString打印时暂时不要打印order中的customer 28 System.out.println(order); 29 } 30 31 tx.commit(); 32 session.close(); 33 } 34 35 /** 36 * 别名查询 37 */ 38 @Test 39 public void test2(){ 40 Session session = HibernateUtil.openSession(); 41 Transaction tx = session.beginTransaction(); 42 43 Query<Order> query = session.createQuery("select o from Order o", Order.class); 44 List<Order> list = query.list(); 45 for (Order order : list) { 46 System.out.println(order); 47 } 48 49 tx.commit(); 50 session.close(); 51 } 52 53 /** 54 * 条件查询 55 */ 56 @Test 57 public void test31(){ 58 Session session = HibernateUtil.openSession(); 59 Transaction tx = session.beginTransaction(); 60 61 Query<Order> query = session.createQuery("from Order where orderno = ‘201709070001‘", Order.class); 62 List<Order> list = query.list(); 63 for (Order order : list) { 64 System.out.println(order); 65 } 66 67 tx.commit(); 68 session.close(); 69 } 70 71 /** 72 * 条件查询2 73 */ 74 @Test 75 public void test32(){ 76 Session session = HibernateUtil.openSession(); 77 Transaction tx = session.beginTransaction(); 78 79 Query<Order> query = session.createQuery("from Order where orderno = ?", Order.class); 80 query.setParameter(0, "201709070001"); 81 List<Order> list = query.list(); 82 for (Order order : list) { 83 System.out.println(order); 84 } 85 86 tx.commit(); 87 session.close(); 88 } 89 90 /** 91 * 具名查询 92 */ 93 @Test 94 public void test4(){ 95 Session session = HibernateUtil.openSession(); 96 Transaction tx = session.beginTransaction(); 97 98 Query<Order> query = session.createQuery("from Order where orderno = :orderno", Order.class); 99 query.setParameter("orderno", "201709070001"); 100 List<Order> list = query.list(); 101 for (Order order : list) { 102 System.out.println(order); 103 } 104 105 tx.commit(); 106 session.close(); 107 } 108 109 /** 110 * 分页查询 111 */ 112 @Test 113 public void test5(){ 114 Session session = HibernateUtil.openSession(); 115 Transaction tx = session.beginTransaction(); 116 117 Query<Order> query = session.createQuery("from Order", Order.class); 118 //设置起始行,从0开始 119 query.setFirstResult(2); 120 //设置查询行数 121 query.setMaxResults(2); 122 List<Order> list = query.list(); 123 for (Order order : list) { 124 System.out.println(order); 125 } 126 127 tx.commit(); 128 session.close(); 129 } 130 131 /** 132 * 查询排序 133 */ 134 @Test 135 public void test6(){ 136 Session session = HibernateUtil.openSession(); 137 Transaction tx = session.beginTransaction(); 138 139 Query<Order> query = session.createQuery("from Order order by id desc", Order.class); 140 List<Order> list = query.list(); 141 for (Order order : list) { 142 System.out.println(order); 143 } 144 145 tx.commit(); 146 session.close(); 147 } 148 149 /** 150 * 聚合查询:同样也支持max、min、avg、sum等聚合函数 151 */ 152 @Test 153 public void test7(){ 154 Session session = HibernateUtil.openSession(); 155 Transaction tx = session.beginTransaction(); 156 157 Query<Long> query = session.createQuery("select count(*) from Order", Long.class); 158 159 /*List<Long> list = query.list(); 160 Long count = list.get(0); 161 System.out.println(count);*/ 162 Long count = query.uniqueResult(); 163 System.out.println(count); 164 165 tx.commit(); 166 session.close(); 167 } 168 169 /** 170 * 投影查询(查询局部字段) 171 */ 172 @Test 173 public void test81(){ 174 Session session = HibernateUtil.openSession(); 175 Transaction tx = session.beginTransaction(); 176 177 Query<Object[]> query = session.createQuery("select orderno,productName from Order", Object[].class); 178 List<Object[]> list = query.list(); 179 for (Object[] objects : list) { 180 for (Object object : objects) { 181 System.out.print(object+" "); 182 } 183 System.out.println(); 184 } 185 186 tx.commit(); 187 session.close(); 188 } 189 190 /** 191 * 投影查询2(查询局部字段) 192 */ 193 @Test 194 public void test82(){ 195 Session session = HibernateUtil.openSession(); 196 Transaction tx = session.beginTransaction(); 197 198 //注意创建对应的两个参数的构造方法 199 Query<Order> query = session.createQuery("select new com.qfedu.hibernate.pojo.Order(orderno,productName) from Order", Order.class); 200 List<Order> list = query.list(); 201 for (Order order : list) { 202 System.out.println(order); 203 } 204 205 tx.commit(); 206 session.close(); 207 } 208 }
2. HQL多表查询
2.1. 多表查询分类
1)内连接查询: inner join
2)左连接查询: left join
3)右连接查询:right join
2.2 HQL多表查询
需求: 同时显示客户名称和订单名称
1 /** 2 * 演示HQL的查询(多表查询) 3 * 1)内连接查询 4 * 2)左连接查询 5 * 3)右连接查询 6 * 7 */ 8 public class HQLTest2 { 9 10 /** 11 * 内连接查询 12 * 效果:只会显示满足条件的数据 13 */ 14 @Test 15 public void test1(){ 16 Session session = HibernateUtil.openSession(); 17 Transaction tx = session.beginTransaction(); 18 //需求:显示客户名称和订单产品名称 19 Query<Object[]> query = session.createQuery("select c.name,o.productName from Customer c inner join c.orders o", Object[].class); 20 List<Object[]> list = query.list(); 21 for (Object[] objects : list) { 22 for (Object object : objects) { 23 System.out.print(object+" "); 24 } 25 System.out.println(); 26 } 27 tx.commit(); 28 session.close(); 29 } 30 31 /** 32 * 左连接查询 33 * 效果:左边的数据全部显示 34 */ 35 @Test 36 public void test2(){ 37 Session session = HibernateUtil.openSession(); 38 Transaction tx = session.beginTransaction(); 39 //需求:显示客户名称和订单产品名称 40 Query<Object[]> query = session.createQuery("select c.name,o.productName from Customer c left join c.orders o", Object[].class); 41 List<Object[]> list = query.list(); 42 for (Object[] objects : list) { 43 for (Object object : objects) { 44 System.out.print(object+" "); 45 } 46 System.out.println(); 47 } 48 tx.commit(); 49 session.close(); 50 } 51 52 /** 53 * 右连接查询 54 * 效果:右边的数据全部显示(和上个测试用例的效果一致) 55 */ 56 @Test 57 public void test3(){ 58 Session session = HibernateUtil.openSession(); 59 Transaction tx = session.beginTransaction(); 60 //需求:显示客户名称和订单产品名称 61 Query<Object[]> query = session.createQuery("select c.name,o.productName from Order o right join o.customer c", Object[].class); 62 List<Object[]> list = query.list(); 63 for (Object[] objects : list) { 64 for (Object object : objects) { 65 System.out.print(object+" "); 66 } 67 System.out.println(); 68 } 69 tx.commit(); 70 session.close(); 71 } 72 }
二. QBC查询
1. QBC查询介绍
Query By Criteria 使用 Criteria
对象进行查询
特点:面向对象方式的查询
注意:5.2版本以后被废弃,推荐使用 JPA Criteria
1 /** 2 * 演示Criteria的查询(单表查询) 3 * 1)全表查询 4 * 2)条件查询 5 * 3)分页查询 6 * 4)查询排序 7 * 5)聚合查询 8 * 6)投影查询 9 * 10 * //@deprecated (since 5.2) for Session, use the JPA Criteria 11 */ 12 public class QBCTest { 13 /** 14 * 全表查询 15 */ 16 @Test 17 public void test1(){ 18 Session session = HibernateUtil.openSession(); 19 Transaction tx = session.beginTransaction(); 20 Criteria ce = session.createCriteria(Customer.class); 21 List<Customer> list = ce.list(); 22 for (Customer customer : list) { 23 System.out.println(customer.getName()); 24 } 25 tx.commit(); 26 session.close(); 27 } 28 29 /** 30 * 条件查询 31 */ 32 @Test 33 public void test21(){ 34 Session session = HibernateUtil.openSession(); 35 Transaction tx = session.beginTransaction(); 36 Criteria ce = session.createCriteria(Order.class); 37 //添加查询条件 orderno = ‘201709070002‘ 38 ce.add( Restrictions.eq("orderno", "201709070002") ); 39 List<Order> list = ce.list(); 40 for (Order order : list) { 41 System.out.println(order.getProductName()); 42 } 43 tx.commit(); 44 session.close(); 45 } 46 47 /** 48 * 条件查询2(多条件) 49 */ 50 @Test 51 public void test22(){ 52 Session session = HibernateUtil.openSession(); 53 Transaction tx = session.beginTransaction(); 54 Criteria ce = session.createCriteria(Order.class); 55 //添加查询条件 orderno like ‘%2017%‘ and productName like ‘%JavaWeb%‘ 56 ce.add( Restrictions.and( Restrictions.like("orderno", "%2017%") , Restrictions.like("productName", "%JavaWeb%") ) ); 57 List<Order> list = ce.list(); 58 for (Order order : list) { 59 System.out.println(order.getProductName()); 60 } 61 tx.commit(); 62 session.close(); 63 } 64 65 /** 66 * 分页查询 67 */ 68 @Test 69 public void test3(){ 70 Session session = HibernateUtil.openSession(); 71 Transaction tx = session.beginTransaction(); 72 Criteria ce = session.createCriteria(Order.class); 73 //分页查询 74 ce.setFirstResult(2);//起始行 75 ce.setMaxResults(2);//查询行数 76 List<Order> list = ce.list(); 77 for (Order order : list) { 78 System.out.println(order.getProductName()); 79 } 80 tx.commit(); 81 session.close(); 82 } 83 84 /** 85 * 查询排序 86 */ 87 @Test 88 public void test4(){ 89 Session session = HibernateUtil.openSession(); 90 Transaction tx = session.beginTransaction(); 91 Criteria ce = session.createCriteria(Order.class); 92 //排序 order by id desc 93 //因为我们的项目中也定义了Order类,所以这里的Order使用全名 94 ce.addOrder(org.hibernate.criterion.Order.desc("id")); 95 List<Order> list = ce.list(); 96 for (Order order : list) { 97 System.out.println(order); 98 } 99 tx.commit(); 100 session.close(); 101 } 102 103 /** 104 * 聚合查询 105 */ 106 @Test 107 public void test5(){ 108 Session session = HibernateUtil.openSession(); 109 Transaction tx = session.beginTransaction(); 110 Criteria ce = session.createCriteria(Order.class); 111 //查询总记录数 select count(id) 112 //ce.setProjection(Projections.rowCount()); 113 ce.setProjection(Projections.count("id")); 114 Long count = (Long)ce.uniqueResult(); 115 116 //查询id的最大值 117 //ce.setProjection(Projections.max("id")); 118 //Integer count = (Integer)ce.uniqueResult(); 119 120 System.out.println(count); 121 tx.commit(); 122 session.close(); 123 } 124 125 /** 126 * 投影查询 127 */ 128 @Test 129 public void test6(){ 130 Session session = HibernateUtil.openSession(); 131 Transaction tx = session.beginTransaction(); 132 Criteria ce = session.createCriteria(Order.class); 133 //投影操作 134 ProjectionList pList = Projections.projectionList(); 135 pList.add(Property.forName("orderno")); 136 pList.add(Property.forName("productName")); 137 ce.setProjection(pList); 138 List<Object[]> list = ce.list(); 139 for (Object[] objects : list) { 140 for (Object object : objects) { 141 System.out.print(object+" "); 142 } 143 System.out.println(); 144 } 145 146 tx.commit(); 147 session.close(); 148 } 149 }
三. 本地SQL查询
1. Hibernate使用SQL语句介绍
本地sql查询可以直接执行 SQL 语句
-
5.2以后推荐使用
createNativeQuery
-
5.2之前使用
createSQLQuery
2. Hibernate使用SQL语句
1 /** 2 * 演示本地 SQL 的查询 3 */ 4 public class SQLTest { 5 /** 6 * 5.2开始支持 7 */ 8 @Test 9 public void test1() { 10 Session session = HibernateUtil.openSession(); 11 Transaction tx = session.beginTransaction(); 12 NativeQuery<Order> sqlQuery = session.createNativeQuery("select * from t_order", Order.class); 13 List<Order> list = sqlQuery.list(); 14 for (Order order : list) { 15 System.out.println(order); 16 } 17 tx.commit(); 18 session.close(); 19 } 20 21 /** 22 * 5.2之前的用法 23 * 以JavaBean对象封装 24 */ 25 @Test 26 public void test2() { 27 Session session = HibernateUtil.openSession(); 28 Transaction tx = session.beginTransaction(); 29 SQLQuery sqlQuery = session.createSQLQuery("select * from t_order"); 30 //封装成Order对像 31 sqlQuery.addEntity(Order.class); 32 List<Order> list = sqlQuery.list(); 33 for (Order order : list) { 34 System.out.println(order); 35 } 36 tx.commit(); 37 session.close(); 38 } 39 40 /** 41 * 5.2之前的用法 42 * 以对象数组封装 43 */ 44 @Test 45 public void test3() { 46 Session session = HibernateUtil.openSession(); 47 Transaction tx = session.beginTransaction(); 48 SQLQuery sqlQuery = session.createSQLQuery("select * from t_order"); 49 List<Object[]> list = sqlQuery.list(); 50 for(Object[] order : list) { 51 for(Object column : order) { 52 System.out.print(column); 53 System.out.print(" "); 54 } 55 System.out.println(); 56 } 57 tx.commit(); 58 session.close(); 59 } 60 }
延迟加载是为了减少程序和数据库的访问次数,提高程序的执行性能。
延迟加载的执行机制:
1)在查询一个对象的时候,不会到数据库查询对象的属性或者其关联的数据
2)在需要使用到对象的属性或关联数据的才会去查询数据库!
按需加载!
1. 类级别的(属性)延迟加载
1 public class LazyLoadingTest { 2 /** 3 * 类级别 延迟加载 4 */ 5 @Test 6 public void test1(){ 7 8 Session session = HibernateUtil.openSession(); 9 Transaction tx = session.beginTransaction(); 10 11 //get():get方法不支持类级别的延迟加载 12 /* 13 Customer cust = session.get(Customer.class, 1);//debug:此行查询了数据库 14 System.out.println(cust.getName()); 15 */ 16 17 //load():load方法支持类级别的延迟加载 18 Customer cust = session.load(Customer.class, 1);//debug:此行没有查询数据库 19 System.out.println(cust.getName());//debug:此行查询了数据库 20 21 tx.commit(); 22 session.close(); 23 24 } 25 }
结论:
load():只有 load 方法才支持类级别的延迟加载
get():get 方法不支持类级别的延迟加载
使用 load() 方法的默认延迟加载策略是延迟加载,可以在配置文件中修改延迟加载策略
<class name="Customer" table="t_customer" lazy="false">
2. 关联级别的
注意: 测试前先删除前面配置的lazy = "false"
以一对多为例
测试:
1 /** 2 * 关联级别 延迟加载(一方:<set/>) 3 * 修改一对多的延迟加载配置:<set name="orders" inverse="true" lazy="false"> 4 */ 5 @Test 6 public void test2(){ 7 8 Session session = HibernateUtil.openSession(); 9 Transaction tx = session.beginTransaction(); 10 11 Customer cust = session.get(Customer.class, 1L); 12 //关联订单 13 System.out.println(cust.getOrders().size()); //延迟加载的 14 15 tx.commit(); 16 session.close(); 17 18 }
结论:
类级别默认使用延迟加载策略,如果不想使用延迟加载策略,那么可以在配置文件中修改延迟加载策略:Customer.hbm.xml
<set name="orders" cascade="all" inverse="true" lazy="false">
多方 <many-to-one/>
1 /** 2 * 关联级别 延迟加载(多对一:<many-to-one/>) 3 * 修改多对一延迟加载配置:<many-to-one name="customer" class="Customer" column="customer_id" cascade="all" lazy="false"/> 4 */ 5 @Test 6 public void test3(){ 7 8 Session session = HibernateUtil.openSession(); 9 Transaction tx = session.beginTransaction(); 10 11 Order order = session.get(Order.class, 1L); 12 System.out.println(order.getCustomer().getName()); // 延迟加载 13 14 tx.commit(); 15 session.close(); 16 }
结论:
类级别默认使用延迟加载策略,如果不想使用延迟加载策略,那么可以在配置文件中修改延迟加载策略:Order.hbm.xml
<many-to-one name="customer" class="Customer" column="customer_id" cascade="all" lazy="false"/>
五. 抓取策略
抓取策略,是为了改变 SQL 语句查询的方式,从而提高 SQL 语句查询的效率(优 化 SQL 语句)
可以设置以下三个值:
1. 查询一方单条记录:<set/>
在Customer.hbm.xml中配置 fetch="select"
<set name="orders" cascade="all" inverse="true" fetch="select">
配置 fetch="join"
会执行一条左外连接的sql语句。
注意:
<set name="orders" cascade="all" inverse="true" fetch="join">
测试
1 public class FetchingStrategyTest { 2 /** 3 * 一方:<set/> 4 * fetch="select" : 默认情况,执行两条sql语句 5 * fetch="join": 把两条sql合并成左外连接查询(效率更高) 6 * 注意:如果配置了join,那么延迟加载就会失效! 7 */ 8 @Test 9 public void test1(){ 10 11 Session session = HibernateUtil.openSession(); 12 Transaction tx = session.beginTransaction(); 13 14 Customer cust = session.get(Customer.class, 1L); 15 System.out.println(cust.getOrders()); 16 17 tx.commit(); 18 session.close(); 19 20 } 21 }
2. 查询一方多条记录: <set/>
此时无论设置 fetch="select"
还是 fetch="join"
,都会执行多条sql语句(n+1)
可以设置 fetch="subselect"
,会执行一条带有子查询的sql语句:
<set name="orders" cascade="all" inverse="true" fetch="subselect">
测试
1 /** 2 * 一方:<set/> 3 * 需求:在查询多个一方(客户列表)的数据,关联查询多方(订单)的数据 4 * 如果fetch的配置是select或join的时候,一共发出n+1条sql语句 5 * fetch="subselect": 使用子查询进行关联查询 6 */ 7 @Test 8 public void test2(){ 9 10 Session session = HibernateUtil.openSession(); 11 Transaction tx = session.beginTransaction(); 12 13 Query<Customer> query = session.createQuery("from Customer", Customer.class); 14 List<Customer> list = query.list(); 15 for (Customer customer : list) { 16 System.out.println(customer.getOrders().size()); 17 } 18 19 tx.commit(); 20 session.close(); 21 22 }
Order.hbm.xml中配置 fetch="select"
会执行两条sql
<many-to-one name="customer" class="Customer" column="customer_id" cascade="all" fetch="select"/>
配置 fetch="join"
注意:如果配置了join,那么延迟加载就会失效!
<many-to-one name="customer" class="Customer" column="customer_id" cascade="all" fetch="join"/>
测试:
1 /** 2 * 多方:<many-to-one/> 3 * fetch="select" : 默认情况,执行两条sql语句(支持延迟加载) 4 * fetch="join": 把两条sql合并成左外连接查询(效率更高) 5 * 注意:如果配置了join,那么延迟加载就会失效! 6 */ 7 @Test 8 public void test3(){ 9 10 Session session = HibernateUtil.openSession(); 11 Transaction tx = session.beginTransaction(); 12 13 Order order = session.get(Order.class, 1); 14 System.out.println(order.getCustomer()); 15 16 tx.commit(); 17 session.close(); 18 19 }
-
-
Hibernate查询缓存
-
Hibernate整合c3p0
六. 整合连接池
1. 导入 c3p0 的整合相关包
在hibernate解压目录下 lib/optional/c3p0 中可以找到整合相关的包
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-c3p0</artifactId> <version>5.2.10.Final</version> </dependency>
2. 在Hibernate.cfg.xml添加整合配置
在连接数据库参数的后面添加:
1 <!-- 整合c3p0:必要 --> 2 <property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property> 3 <!-- c3p0详细配置:可选 --> 4 <property name="c3p0.min_size">10</property> 5 <property name="c3p0.max_size">20</property>
1 public class PoolTest { 2 /** 3 * 演示连接池的整合 4 */ 5 @Test 6 public void test1(){ 7 8 Session session = HibernateUtil.openSession(); 9 session.doWork(new Work(){ 10 @Override 11 public void execute(Connection connection) throws SQLException { 12 System.out.println(connection); 13 } 14 15 }); 16 17 session.close(); 18 } 19 }
七.二级缓存
Hibernate 的一级缓存:就是 Session 对象的缓存,而 Session 对象在每次操作之 后都会关闭,那么一级缓存就丢失!
结论 :一级缓存只用于一次业务操作内的缓存。
Hibernate 的二级缓存:就是 SessionFactory 的缓存,二级缓存和 SessionFactory 对象的生命周期是一致的,SessionFactory 不消耗,那么二级缓存的数据就不会 丢失!
结论:二级缓存可以用于多次业务操作的缓存。
多个Session 可以共同使用二级缓存
注意的问题:
1)Hibernate 一级缓存默认是开启的,而且无法关闭。
2)Hibernate 二级缓存默认是关闭的,如果使用需要开启,而且需要引入第三 方的缓存工具,例如 EhCache 等。
1. 添加二级缓存需要实现jar包
jar包位置: hibernate解压目录下 lib/optional/ehcache下找到相关包!
maven项目,pom文件添加
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>5.2.10.Final</version> </dependency>
2. 配置二级缓存
在hibernate.cfg.xml中配置以下节点:
1.property
节点 要放在 mapping
节点的上方
1 <!-- 开启 Hibernate 的二级缓存 --> 2 <property name="hibernate.cache.use_second_level_cache">true</property> 3 <!-- 引入 EhCache 的工具 --> 4 <property name="hibernate.cache.region.factory_class"> 5 org.hibernate.cache.ehcache.EhCacheRegionFactory 6 </property>
<!-- 需要缓存哪个类 --> <class-cache usage="read-only" class="pojo.Customer"/>
3. 测试
使用二级缓存只打印1条sql,不使用二级缓存会打印2条sql
1 public class CacheLevelTwoTest { 2 /** 3 * 演示二级缓存 4 * hibernate查询策略,如果二级缓存开启,则先到二级缓存中查询,如果查不到,则到session中查询,如果查 5 * 不到,则到数据库中查询,然后查询结果,放入一级缓存和二级缓存中,以备下次查询使用 6 */ 7 @Test 8 public void test1(){ 9 10 Session session = HibernateUtil.openSession(); 11 12 //第1次操作 13 Customer cust = session.get(Customer.class, 1L); 14 System.out.println(cust.getName()); 15 16 //关闭session 17 session.close(); 18 19 //第2次操作 20 session = HibernateUtil.openSession(); 21 cust = session.get(Customer.class, 1L); 22 System.out.println(cust.getName()); 23 24 session.close(); 25 } 26 }
以上是关于Hibernate查询以及优化策略04的主要内容,如果未能解决你的问题,请参考以下文章