Hibernate的基础入门--笔记(四)
1.Hibernate的检索方式(查询的方式,抓取方式)
明确:
它是在我们在开发中实现功能的手段.
hibernate中一共有5种检索方式:
OID查询:
涉及的方法:
get(Class clazz,Serializable); 根据id查询一个实体
特点: 采用的是立即加载的策略.不管用不用,马上发起查询.
它是不可改变的,永远都是立即加载.
返回的是实体类对象
load(Class clazz,Serializable); 根据id查询一个实体
特点: 采用延迟加载的策略.什么时候用,什么时候发起查询.
它是可以通过配置的方式改变的.可以配置成立即加载,默认是延迟加载.
配置的位置是实体类的映射文件中class标签 返回的实体类的代理对象
属性:lazy. 含义:是否采用延迟加载. 取值:true 延迟加载(默认)/false(立即加载)
1 <hibernate-mapping package="com.gcl.domain"> 2 <class name="Customer" table="cst_customer" lazy="false"> 3 <id name="custId" column="cust_id"> 4 <generator class="native"></generator> 5 </id>
关于使用load延迟加载的问题:

注:在不改变原有代码的情况下,对已有的方法进行增强,使用动态代理.
对象导航查询:
明确:
只有有关联关系的实体之间才能使用对象导航查询.
特点:
是使用当前实体中关联关系属性的get方法来进行查询.
学习对象导航查询,要做思想的转变.
1 2 /** 3 * 根据Id查询一个客户信息 4 * @param custId 5 * @return 6 */ 7 public Customer findByCustomerId(Long custId){ 8 Session s = HibernateUtil.getCurrentSession(); 9 Transaction tx = s.beginTransaction(); 10 Customer c1 = s.get(Customer.class, custId); 11 tx.commit(); 12 return c1; 13 } 14 /** 15 * 需求: 16 * 查询id为1的客户下的所有联系人 17 */ 18 @Test 19 public void test2(){ 20 Customer c = findByCustomerId(1L); 21 Set set = c.getLinkmans();//对象导航查询 ---查询的就是客户下的所有联系人. 22 for(Object o : set){ 23 System.out.println(o); 24 } 25 } 26 27 /** 28 * 需求: 29 * 查询id为1的联系人所属的客户 30 */ 31 @Test 32 public void test3(){ 33 Session s = HibernateUtil.getCurrentSession(); 34 Transaction tx = s.beginTransaction(); 35 LinkMan l = s.get(LinkMan.class, 1L); 36 System.out.println(l); 37 System.out.println(l.getCustomer()); //对象导航查询 ----查的是当前联系人所属的客户 38 tx.commit(); 39 }
HQL查询(比较有用):
1 /** 2 * hibernate的检索方式: 3 * HQL查询 4 * @author zhy 5 * 6 */ 7 public class HibernateDemo3 { 8 9 /** 10 * 基本查询 11 */ 12 @Test 13 public void test1(){ 14 Session s = HibernateUtil.getCurrentSession(); 15 Transaction tx = s.beginTransaction(); 16 //1.获取Query对象 17 Query query = s.createQuery("from Customer"); 18 List list = query.list(); 19 tx.commit(); 20 for(Object o : list){ 21 System.out.println(o); 22 } 23 } 24 25 /** 26 * 条件查询 27 */ 28 @Test 29 public void test2(){ 30 Session s = HibernateUtil.getCurrentSession(); 31 Transaction tx = s.beginTransaction(); 32 //1.获取Query对象 33 Query query = s.createQuery("from Customer where custName like ? and custLevel = ? "); 34 //2.使用索引位置设置条件 35 query.setString(0, "%集%"); 36 query.setString(1, "22"); 37 List list = query.list(); 38 tx.commit(); 39 for(Object o : list){ 40 System.out.println(o); 41 } 42 } 43 44 /** 45 * 具名查询 46 * 给查询语句中的占位符提供一个具体的名称 47 */ 48 @Test 49 public void test3(){ 50 Session s = HibernateUtil.getCurrentSession(); 51 Transaction tx = s.beginTransaction(); 52 //1.获取Query对象 53 Query query = s.createQuery("from Customer where custName like :custName and custLevel = :custLevel "); 54 //2.使用索引位置设置条件 55 query.setString("custName", "%集%"); 56 query.setString("custLevel", "23"); 57 List list = query.list(); 58 tx.commit(); 59 for(Object o : list){ 60 System.out.println(o); 61 } 62 } 63 64 /** 65 * 排序查询 66 * 使用的关键字:order by 67 * 默认情况下是:升序asc 68 * 降序:desc 69 */ 70 @Test 71 public void test4(){ 72 Session s = HibernateUtil.getCurrentSession(); 73 Transaction tx = s.beginTransaction(); 74 //1.获取Query对象 75 Query query = s.createQuery("from LinkMan order by lkmId desc "); 76 List list = query.list(); 77 tx.commit(); 78 for(Object o : list){ 79 System.out.println(o); 80 } 81 } 82 83 84 /** 85 * 分页查询 86 * MySQL分页的关键字:limit 87 * Limit后面有两个参数:查询的开始索引,查询的最大条数 88 * hibernate中提供了两个方法: 89 * setFirstResult(int firstResult):查询的开始索引 90 * setMaxResults(int maxResults):查询的最大条数 91 * 92 * 开始记录索引的计算方式: 93 * (当前页 - 1) * 每页显示的条数 94 * 95 * 需求: 96 * 每页显示2条 97 */ 98 @Test 99 public void test5(){ 100 Session s = HibernateUtil.getCurrentSession(); 101 Transaction tx = s.beginTransaction(); 102 //1.获取Query对象 103 Query query = s.createQuery("from LinkMan "); 104 //2.设置开始记录索引和每页显示的条数 105 query.setFirstResult(4); 106 query.setMaxResults(2); 107 List list = query.list(); 108 tx.commit(); 109 for(Object o : list){ 110 System.out.println(o); 111 } 112 } 113 114 /** 115 * 统计查询 116 * 它的应用场景 117 * 全都是和聚合函数相关的 118 * 在开发中分页时,需要有一个查询总记录条数的方法,就用到了聚合函数。 119 * 120 * 在count(*)和count(主键)之间,我们实际开发中尽量选择count(主键) 121 * 他俩的执行结果是一样的。 122 */ 123 @Test 124 public void test6(){ 125 Session s = HibernateUtil.getCurrentSession(); 126 Transaction tx = s.beginTransaction(); 127 //1.获取Query对象 128 Query query = s.createQuery("select count(lkmId) from LinkMan"); 129 List list = query.list(); 130 tx.commit(); 131 for(Object o : list){ 132 System.out.println(o); 133 } 134 } 135 136 /** 137 * 投影查询 138 * 当我们查询一个实体的部分信息时,返回的不再是一个实体类封装的集合,而是由Object数组组成的。 139 * 这时我们获取数据时,只能使用数组下标,不再方便。 140 * 为了使操作方便,仍然想让其返回的是由实体类组成的集合。 141 * 这种方式就是查询对象的投影。 142 * 使用要求: 143 * 查询的HQL语句:必须是 new 实体类(查询的字段) 144 * 实体类中:必须提供对应参数列表的构造函数。 145 * 使用细节: 146 * 如果当前工程中,查询的实体类名唯一,可以直接写类名。 147 * 如果不唯一,则必须写全限定类名 148 */ 149 @Test 150 public void test8(){ 151 Session s = HibernateUtil.getCurrentSession(); 152 Transaction tx = s.beginTransaction(); 153 //1.获取Query对象 154 Query query = s.createQuery("select new Customer(custId,custName) from Customer "); 155 List list = query.list(); 156 tx.commit(); 157 for(Object o : list){ 158 System.out.println(o); 159 } 160 161 } 162 @Test 163 public void test7(){ 164 Session s = HibernateUtil.getCurrentSession(); 165 Transaction tx = s.beginTransaction(); 166 //1.获取Query对象 167 Query query = s.createQuery("select custId,custName from Customer "); 168 List<Object[]> list = query.list(); 169 tx.commit(); 170 for(Object[] os : list){ 171 System.out.println("------每个数组中的内容------"); 172 for(Object o : os){ 173 System.out.println(o); 174 } 175 } 176 } 177 178 /** 179 * 连接查询之: 180 * 左外连接查询和迫切左外连接查询的区别 181 * 我们此处要明确的事情是: 182 * 左外连接和迫切左外连接之间有什么区别。 183 * 而在以后的开发中,能用连接查询的,绝大多数情况下都可以使用对象导航查询。 184 * 185 * SQL语句中: 186 * 有几种连接方式: 187 * 交叉连接:cross join 188 * 返回的是两张表的笛卡尔积 189 * 内连接: inner join 190 * 返回的是两张表符合条件的记录 191 * 左外连接和右外连接: left outer join 和 right outer join 192 * 左外连接返回的是除了符合条件的之外,还有左表的其他数据(一定返回左表所有数据) 193 * 关于子查询和表连接的执行效率问题: 194 * 子查询的效率高 195 * 196 * Hibernate中: 197 * 左外连接和迫切左外连接的区别就是返回的数据不同 198 * 左外连接返回的是一个数组 199 * 数组中包含的是一个左表实体对象和一个右表实体对象 200 * 迫切左外连接查询返回的是: 201 * 返回的是左表实体类对象。有可能重复。使用时需要去重。 202 */ 203 @Test 204 public void test10(){ 205 Session s = HibernateUtil.getCurrentSession(); 206 Transaction tx = s.beginTransaction(); 207 //1.获取Query对象 208 Query query = s.createQuery(" from Customer c left outer join fetch c.linkmans "); 209 List list = query.list(); 210 tx.commit(); 211 for(Object o : list){ 212 System.out.println(o); 213 } 214 } 215 216 217 @Test 218 public void test9(){ 219 Session s = HibernateUtil.getCurrentSession(); 220 Transaction tx = s.beginTransaction(); 221 //1.获取Query对象 222 Query query = s.createQuery(" from Customer c left outer join c.linkmans "); 223 List<Object[]> list = query.list(); 224 tx.commit(); 225 for(Object[] os : list){ 226 System.out.println("-------数组的内容---------"); 227 for(Object o : os){ 228 System.out.println(o); 229 } 230 } 231 232 } 233 }
QBC查询(特定情况下有用):
1 /** 2 * hibernate的检索方式: 3 * QBC查询 4 * @author zhy 5 * 6 */ 7 public class HibernateDemo4 { 8 9 /** 10 * 基本使用 11 */ 12 @Test 13 public void test1(){ 14 Session s = HibernateUtil.getCurrentSession(); 15 Transaction tx = s.beginTransaction(); 16 //1.获取Criteria对象 17 Criteria c = s.createCriteria(Customer.class); 18 //2.执行方法获取结果集 19 List list = c.list(); 20 tx.commit(); 21 for(Object o : list){ 22 System.out.println(o); 23 } 24 } 25 26 /** 27 * 条件查询 28 */ 29 @Test 30 public void test2(){ 31 Session s = HibernateUtil.getCurrentSession(); 32 Transaction tx = s.beginTransaction(); 33 //1.获取Criteria对象 34 Criteria c = s.createCriteria(Customer.class); 35 //2.使用add方法,添加约束 36 c.add(Restrictions.eq("custSource", "6")); 37 c.add(Restrictions.like("custName", "%集%")); 38 //3.执行方法获取结果集 39 List list = c.list(); 40 tx.commit(); 41 for(Object o : list){ 42 System.out.println(o); 43 } 44 } 45 46 /** 47 * 排序查询 48 * 涉及的方法: 49 * addOrder(Order order); 50 * Order类: 51 * hibernate中的排序类 52 * 提供了 53 * asc(String propertyName):按照指定属性名称升序排序 54 * desc(String propertyName):按照指定属性名称降序排序 55 */ 56 @Test 57 public void test3(){ 58 Session s = HibernateUtil.getCurrentSession(); 59 Transaction tx = s.beginTransaction(); 60 //1.获取Criteria对象 61 Criteria c = s.createCriteria(Customer.class); 62 //2.添加排序 63 c.addOrder(Order.desc("custId")); 64 //3.执行方法获取结果集 65 List list = c.list(); 66 tx.commit(); 67 for(Object o : list){ 68 System.out.println(o); 69 } 70 } 71 72 73 /** 74 * 统计查询 75 * 使用聚合函数 76 * 用count(主键)为例。 77 * 涉及的方法: 78 * setProjection(Projection projection); 79 * 涉及的类: 80 * Projections 81 */ 82 @Test 83 public void test4(){ 84 Session s = HibernateUtil.getCurrentSession(); 85 Transaction tx = s.beginTransaction(); 86 //1.获取Criteria对象 87 Criteria c = s.createCriteria(Customer.class);//from Customer 查询所有 88 //2.要把select custId from Customer转成 select count(custId) from Customer; 89 c.setProjection(Projections.count("custId")); 90 //3.执行方法获取结果集 91 List list = c.list(); 92 tx.commit(); 93 for(Object o : list){ 94 System.out.println(o); 95 } 96 } 97 98 /** 99 * 分页查询 100 * 和HQL查询中涉及的方法以及方法的含义是一模一样的 101 */ 102 @Test 103 public void test5(){ 104 Session s = HibernateUtil.getCurrentSession(); 105 Transaction tx = s.beginTransaction(); 106 //1.获取Criteria对象 107 Criteria c = s.createCriteria(LinkMan.class);//from LinkMan 查询所有 108 //2.设置分页的条件 109 c.setFirstResult(6); 110 c.setMaxResults(2); 111 //3.执行方法获取结果集 112 List list = c.list(); 113 tx.commit(); 114 for(Object o : list){ 115 System.out.println(o); 116 } 117 } 118 119 /** 120 * 离线查询 121 * 什么是离线: 122 * 它是和在线对应的。 123 * 在获取Criteria对象时,是使用一个可用的Session直接获取的,则该Criteria对象称为在线对象 124 * DetachedCriteria 125 * 它是一个离线对象,获取该对象,不需要session。它和criteria添加条件的方式是一模一样的。 126 * 从而使我们在表现层就可以准备好查询的对象,逐层传递持久层中,在持久层中查询。 127 * 它的使用场景: 128 * 1、多条件查询 129 * 2、在后面学习了spring之后,和spring配合使用 130 */ 131 @Test 132 public void servletFindAll(){ 133 //按照客户名称,客户行业,客户级别和客户来源查询所有客户 134 DetachedCriteria dCriteria = DetachedCriteria.forClass(Customer.class);//获取离线对象,设置查询的实体类字节码 135 //添加条件 136 dCriteria.add(Restrictions.like("custName","%集%")); 137 dCriteria.add(Restrictions.like("custIndustry","%IT%")); 138 dCriteria.add(Restrictions.eq("custLevel","23")); 139 dCriteria.add(Restrictions.eq("custSource","6")); 140 141 142 List<Customer> list = serviceFindAll(dCriteria); 143 for(Customer c : list){ 144 System.out.println(c); 145 } 146 } 147 148 public List<Customer> serviceFindAll(DetachedCriteria dCriteria){ 149 //调用持久层 150 return daoFindAll(dCriteria); 151 } 152 153 public List<Customer> daoFindAll(DetachedCriteria dCriteria){ 154 Session s = HibernateUtil.getCurrentSession(); 155 Transaction tx = s.beginTransaction(); 156 Criteria c = dCriteria.getExecutableCriteria(s);//把离线对象转成了在线对象 157 List list = c.list(); 158 tx.commit(); 159 return list; 160 } 161 162 163 @Test 164 public void test6(){ 165 Session s = HibernateUtil.getCurrentSession(); 166 Transaction tx = s.beginTransaction(); 167 //1.获取Criteria对象 168 Criteria c = s.createCriteria(LinkMan.class);//from LinkMan 查询所有 169 //2.执行方法获取结果集 170 List list = c.list(); 171 tx.commit(); 172 for(Object o : list){ 173 System.out.println(o); 174 } 175 } 176 }
SQL查询(使用hibernate时用的不多):
2.Hibernate中的检索策略(查询的策略,抓取策略)
明确:
用更好的,效率更高的方式来查询.提升性能的手段.
分类:
类级别的检索策略:
当我们查询一个实体时,何时去查询实体类中除OID之外的其它数据.
举例: 查询id为1的客户
涉及的方法:
get: 立即加载 不管用不用,都立即去查询
load: 延迟加载 默认情况下是什么时候用,什么时候查询.可以通过配置的方式改为立即查询
注意:
类级别检索策略只关心当前实体类中包含的数据什么时候查询.不关心关联对象什么时候查询.
关联级别的检索策略
当我们查询一个实体时,何时去查询该实体关联的对象数据.(关联数据可能是一个对象,也有可能是一个集合)
它不关心当前实体什么时候查询.
举例: 查询id为1的客户下的所有联系人
关心的是: 联系人什么时候查
不关心的是: id为1的客户中,除了OID之外的其它信息什么是查询.
关联级别涉及的情况:
一对多/多对多的情况:
解决的问题:
1.什么时候去查询:
延迟加载:什么时候用,什么时候查询
2.用什么方式去查询:
用Hibernate中的方法是对象导航查询.
让Hibernate为我们生成SQL语句,有三种:
第一种:子查询
第二种:左外连接(hibernate中没有右外连接)
第三种:多条SQL语句(实际开发中用这种)
涉及的配置:
全是配置在Set标签上的.
属性:
lazy:是否用延迟加载
取值:
true 延迟加载.(什么时候用,什么时候查询集合对象) 默认值
false 立即加载.(不管用不用,马上查询出来集合对象)
extra 极懒加载.(用什么数据,就查什么数据,不用就不查询)
fetch:生成查询语句的方式
select: 多条SQL语句 默认值
hibernate中的n+1问题:
示例:有四个客户和八个联系人.每个客户2个联系人
需求:查询每个客户的所有联系人
问题:产生了5条SQL语句.
有一条是查询客户的.而在实际情况下我们只需要四条语句.
解决办法:
批量抓取的配置.
属性:
batch-size:含义就是查询时间号的个数.
配置的位置:在set标签上
建议:配置范围在3~10之间

subselect:使用子查询
join:使用左外连接.(当配置了左外连接后,lazy属性就没用了.因为一下就查询了2张表.)
1 /** 2 * 关联级别的检索策略 3 * 在一对多和多对多的情况下 4 * @author zhy 5 * 6 */ 7 public class HibernateDemo1 { 8 9 /** 10 * 需求: 11 * 查询id为1的客户下的所有联系人 12 * 解决的问题: 13 * 什么时候查询: 14 * 延迟加载 15 * 用的什么方式: 16 * 多条SQL语句。 17 * 1条查的客户 18 * 1条查的联系人 19 */ 20 @Test 21 public void test1(){ 22 Session s = HibernateUtil.getCurrentSession(); 23 Transaction tx = s.beginTransaction(); 24 Customer c1 = s.get(Customer.class,1L);//c1什么时候查询是类级别检索策略 25 System.out.println(c1); 26 System.out.println(c1.getLinkmans()); 27 tx.commit(); 28 } 29 30 /** 31 * 需求: 32 * 查询所有客户中每个客户的所有联系人信息 33 */ 34 @Test 35 public void test2(){ 36 Session s = HibernateUtil.getCurrentSession(); 37 Transaction tx = s.beginTransaction(); 38 //1.查询所有客户 39 Query query = s.createQuery("from Customer"); 40 //2.获取结果集 41 List<Customer> cs = query.list(); 42 //3.遍历 43 for(Customer c : cs){ 44 System.out.println(c); 45 System.out.println(c.getLinkmans().size());//有多少个联系人 46 System.out.println(c.getLinkmans()); 47 } 48 tx.commit(); 49 } 50 }
多对一/一对一的情况:
解决的问题:
1.什么时候去查询:
立即加载.(不管用不用都查询出来)
2.用什么方式去查询
用Hibernate中的方法是对象导航查询.
让Hibernate为我们生成SQL语句,有三种:
第一种:左外连接(hibernate中没有右外连接)
第二种:多条SQL语句(实际开发中用这种)
涉及的配置:
全是配置在 many-to-one / one-to-one 标签上的.
属性:
lazy: 是否延迟加载
取值:
false:立即加载.(不管用不用,马上查询出来集合对象)
proxy:看对方类级别的检索策略.如果对方是延迟加载,它就是延迟.如果对方是立即加载,它就是立即.
no-proxy:这个值基本不用.它需要在运行时对字节码进行增强.
fetch:生成查询语句的方式:
select:多条SQL语句
join:使用左外连接.(当配置了左外连接后,lazy属性就没用了.因为一下就查询了2张表.)

1 /** 2 * 关联级别的检索策略 3 * 在多对一和多对多的情况下 4 * @author zhy 5 * 6 */ 7 public class HibernateDemo2 { 8 9 /** 10 * 需求: 11 * 查询id为1的联系人所属客户 12 * 解决的问题: 13 * 什么时候查询: 14 * 用的什么方式: 15 */ 16 @Test 17 public void test1(){ 18 Session s = HibernateUtil.getCurrentSession(); 19 Transaction tx = s.beginTransaction(); 20 LinkMan man1 = s.get(LinkMan.class,1L); 21 System.out.println(man1); 22 System.out.println(man1.getCustomer()); 23 tx.commit(); 24 } 25 26 27 }

浙公网安备 33010602011771号