hibernate04 懒加载、抓取策略、二者结合、session详解、一级缓存、二级缓存、查询缓存

来源:互联网 发布:ubuntu xfce 编辑:程序博客网 时间:2024/06/06 10:03



一、 hibernate提高性能的方式:
       原理: 发出的sql语句越少,性能越高
       方法:
            1、懒加载
            2、抓取策略
            3、缓存策略
            4、HQL语句
            
            
二、 懒加载


     1、类的懒加载
          1、利用session.load方法可以产生代理对象
          2、在session.load方法执行的时候并不发出sql语句
          3、在得到其一般属性的时候发出sql语句
          4、只针对一般属性有效,针对标示符属性是无效的
          5、默认情况就是懒加载
          
     2、集合的懒加载
          false  当session.get时,集合就被加载出来了
          true   在遍历集合的时候才加载,默认
          extra  针对集合做count,min,max,sum等操作,更近一步的懒加载(函数运算)
          
     3、单端关联的懒加载(多对一)
          <many-to-one lazy="false/no-proxy/proxy">  no-porxy 默认值  true
          根据多的一端加载一的一端,就一个数据,所以无所谓


     总结:懒加载主要解决了一个问题:类、集合、many-to-one在时候发出SQL语句,加载数据
     
     
     例:
     ****************************************************************************
     public class LazyTest {
          // 类的懒加载
          @Test
          public void testLoad(){
            SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
            Session session = sessionFactory.openSession();
            Classes classes = (Classes) session.load(Classes.class, 1L);
            session.close();
          }
          
          // 集合的懒加载 情况1:  Classes.hbm.xml的set元素的lazy属性取默认值true
          @Test
          public void testSet_true(){
            SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
            Session session = sessionFactory.openSession();


            Classes classes = (Classes) session.load(Classes.class, 1L);
            Set<Student> students = classes.getStudents();
            for(Student student : students){   // 此时遍历的时候才发出懒加载
              System.out.println(student.getSname());
            }
            
            session.close();
          }
          
          
          // 集合的懒加载 情况2:  Classes.hbm.xml的set元素的lazy属性取值false
          @Test
          public void testSet_false(){
            SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
            Session session = sessionFactory.openSession();


            Classes classes = (Classes) session.load(Classes.class, 1L);  // 此时就发出懒加载
            Set<Student> students = classes.getStudents();
            for(Student student : students){  // 此时遍历的时候才发出懒加载
              System.out.println(student.getSname());
            }
            
            session.close();
          }
          
          // 集合的懒加载 情况3:  Classes.hbm.xml的set元素的lazy属性取值extra 更近一步的懒加载(函数运算)
          @Test
          public void testSet_extra(){
            SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
            Session session = sessionFactory.openSession();


            Classes classes = (Classes) session.load(Classes.class, 1L);  
            Set<Student> students = classes.getStudents();
            System.out.println(students.size());
            
            session.close();
          }    
      }
     
     ****************************************************************************
     
     
     
三、 抓取策略


   1、产生原因
        
        ---------------------------------------------------------------------------       
        public class FetchTest {    
            @Test
            public void testAll_Classes(){
              SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
              Session session = sessionFactory.openSession();
              
              List<Classes> cList = session.createQuery("from Classes").list();
              for(Classes classes:cList){
                Set<Student> students = classes.getStudents();
                for(Student student:students){
                  System.out.println(student.getSname());
                }
              }
              
              session.close();
          }        
        ---------------------------------------------------------------------------
        注:  
              n+1的问题:   
                  先查共有多少班级(1条),再分别查每个班级有多少学生(n条),hibernate自动发出的语句有n+1条
                  抓取策略的产生:  当班级有很多,而每个班级的学生也有很多,此时下面这种方法效率极低
                      


   2、研究的主要是set集合如何提取数据
   
   3、在Classes.hbm.xml文件中
       
       <set fetch="join/select/subselect" />
            join        左外连接  如果把需求分析翻译sql语句,存在子查询,这个时候用该策略不起作用
            select      默认 先查询一的一端,再查询多的一端
            subselect   子查询  如果需要分析翻译成sql语句存在子查询,这个时候用该策略效率最高


   
四、 懒加载与抓取策略结合


    1、 懒加载决定什么时候发出sql语句,抓取策略决定发出几条SQL语句
    
    2、 各种情况见图
        
         
   
    3、 抓取策略是提高查询效率的一种方式,hql语句也能做到
      
      
      
     
     
五、 session详解
      
    1、 session的俩种产生方式
          
          方式1: sessionFactory.openSession: 
                 每次都创建一个新的session
                      
          方式2: sessionFactory.getCurrentSession:
                 原理:
                  先查看当前线程中session是否存在;
                   如果存在,从当前线程中把session取出来
                   如果不存在,新创建一个session,并将其放入高
                       threadLocal中,再由用户从当前线程中取出
      
      
    2、 session.getCurrentSession的用法
          1、在hibernate的配置文件中:
                <property name="current_session_context_class">thread</property>
                
          2、不需要写session.close方法,在事务提交的时候会自动关闭(由hibernate内部完成)
          
          3、crud都需要事务
                1、因为是一个线程,所以整个方法中一个session,一个事务
                2、保证了整个业务操作的安全性 
     
    


六、 session的缓存


    1、缓存
         1、缓存的生命周期
         2、数据库的数据是怎么样放入到缓存中的
         3、缓存中的数据是怎么样放入到数据库中的
         4、客户端怎么样从缓存中把数据取出来
         5、客户端怎么样把一个数据放入到缓存中
         6、怎么样把一个对象从缓存中取出
         7、把缓存中所有的数据清空
         8、页面缓存


    2、session缓存(一级缓存)
         1、生命周期就是session的生命周期
         2、一级缓存存放的数据都是私有数据
              把session存放在threadlocal中,不同的线程是不能访问的,所以保证了数据的安全性
         3、怎么样把数据存放到一级缓存中
              利用session.save/update/load/get方法都可以存放在一级缓存中
         4、利用session.get/load方法可以把数据从一级缓存中取出
         5、session.evict方法可以把一个对象从一级缓存中清空
         6、利用session.clear方法可以把session中的所有的数据清空
         7、利用session.Refresh方法把数据库中的数据同步到缓存中
               
             疑问:  Person person = (Person)session.get(Person.class,1L);
                    person.setPname("aaa");
                    session.refresh();
                    transaction.commit();        
                    原来名称为“BBB”, 可是加过refresh方法之后,数据库中并未改动,
                    
                    原因: 刚开始get的时候在session中建了一个一个person对象,和person快照,
                          set改的是session中的person名字,
                          refresh将数据库中的person刷新到缓存中了,将session中的person覆盖了,
                          此时person与快照一致,使用提交的时候不必发出update语句                         
         
         8、session.flush只是发出SQL语句,刷新缓存中的数据到数据库中,并未清空缓存中的数据
              在session的缓存内部,会去检查所有的持久化对象
                 1、如果一个持久化对象没有ID值,则会发出insert语句
                 2、如果一个持久化对象有ID值,则会去检查快照进行对比,如果一样,则什么都不做,如果不一样,则发出update语句
                 3、检查所有的持久化对象是否有关联对象
                      检查关联对象的级联操作
                      检查关联对象的关系操作
              
         9、批量操作
               例:
               -------------------------------------------------------------------------------------------
                @Test
                public void testSaveBatch(){
                    SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
                    Session session = sessionFactory.getCurrentSession();
                    Transaction transaction = session.beginTransaction();
                    
                    // 插入100万条记录
                    for (int i = 0; i < 100000; i++) {
                        Classes classes = new Classes();
                        classes.setCname("a"+i);
                        classes.setDescription("d"+i);
                        session.save(classes);
                        
                        // 为了避免内存溢出,可以每插入一定量的数据,刷新并情况缓存
                        if(i%50==0){
                            session.flush();
                            session.clear();
                        }
                    }
                    
                    transaction.commit();
                }
                              
               -------------------------------------------------------------------------------------------
          


    3、二级缓存:存放公有数据


         1、适用场合:
              1、数据不能频繁更新
              2、数据能公开,私密性不是很强


         2、hibernate本身并没有提供二级缓存的解决方案


         3、二级缓存的实现是依赖于第三方供应商完成的
               ehcache
               oscache
               jbosscache
               swamchache


         4、二级缓存的操作
               1、二级缓存存在sessionFactory中
               2、生命周期:与sessionFactory保持一致
               3、使用二级缓存的步骤
                   1、在hibernate.cfg.xml
                        <!--  开启二级缓存 -->
                        <property name="cache.use_second_level_cache">true</property>
                        <!-- 二级缓存的提供商 -->
                        <property name="cache.provider_class">
                              org.hibernate.cache.EhCacheProvider
                        </property>
                   2、让某一个对象进入到二级缓存中
                        方式一:在配置文件中
                            <class-cache usage="read-only" class="指定的类对象的路径"/>
                        方式二:在映射文件中
                            <!-- 缓存策略 -->
                            <cache usage="read-only"/>
                   3、使用
                        session.get/session.load
                        
         5、 二级缓存大量数据的解决方案: 
                分页  在src目录下配置cache.xml  将多余的数据存储到磁盘上
              例:
              -------------------------------------------------------------------------
              cache.xml配置信息如下:
                 
                  <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                   xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
              
                      <!-- 自定义的存储路径 -->
                      <diskStore path="D:\\TEMP1"/>
                      <defaultCache
                              maxElementsInMemory="12"
                              eternal="false"
                              timeToIdleSeconds="120"
                              timeToLiveSeconds="120"
                              overflowToDisk="false"
                              maxElementsOnDisk="10000000"
                              diskPersistent="false"
                              diskExpiryThreadIntervalSeconds="120"
                              memoryStoreEvictionPolicy="LRU"
                              />
                              
                      <Cache
                              name="cn.itcast.oneToMany.domain.Classes"
                              maxElementsInMemory="5" 
                              eternal="false"
                              timeToIdleSeconds="120"
                              timeToLiveSeconds="120"
                              overflowToDisk="true"
                              maxElementsOnDisk="10000000"
                              diskPersistent="false"
                              diskExpiryThreadIntervalSeconds="120"
                              memoryStoreEvictionPolicy="LRU"
                              />
                  </ehcache>


              -------------------------------------------------------------------------                            
              @Test
              public void testAllClasses(){
                SessionFactory sessionfactory = HibernateUtils.getSessionFactory();
                Session session = sessionfactory.openSession();
                
                List<Classes> classesList = session.createQuery("from Classes").list();
                session.close();
                
                // 因为磁盘的读写速度太快,所以要休眠会
                try {
                  Thread.sleep(1000);
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }
                
              }
              -------------------------------------------------------------------------
        
        
    4、查询缓存
          1、使用能够查询缓存的步骤:
              1、先开启二级缓存,查询缓存是在二级缓存的基础上执行的
              2、在hibernate.cfg.xml      
                   <!-- 开启查询缓存,默认是关闭的 -->
                   <property name="cache.use_query_cache">true</property>
              3、在客户端
                   Query query.setCacheable(true);


          2、查询缓存只能在createQuery中使用
          3、只有一样是HQL语句才可以使用查询缓存
          例:
            --------------------------------------------------------------------            
            @Test
            public void testQuery(){
              SessionFactory sessionfactory = HibernateUtils.getSessionFactory();
              Session session = sessionfactory.openSession();


              Query query = session.createQuery("from Classes");
              query.setCacheable(true);   // classes里的所有数据要往查询缓存中放了
              List<Classes> classesList = query.list();
              query = session.createQuery("from Classes");
              query.setCacheable(true); // 与上面的query作用不同,是俩个对象
              classesList = query.list();
              
              session.close();
            }           

            --------------------------------------------------------------------




      


  



























































0 0
原创粉丝点击