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 }

 

posted @ 2017-06-03 11:50  细节造就完美  阅读(47)  评论(0)    收藏  举报