• Hibernate之一级缓存和二级缓存


    1:Hibernate的一级缓存:

      1.1:使用一级缓存的目的是为了减少对数据库的访问次数,从而提升hibernate的执行效率;(当执行一次查询操作的时候,执行第二次查询操作,先检查缓存中是否有数据,如果有数据就不查询数据库,直接从缓存中获取数据);

       1.2:Hibernate中的一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数,只在session范围内有效,session关闭,一级缓存失败;

      1.3:一级缓存的特点,只在session范围有效,作用时间短,效果不是特别明显,在短时间内多次操作数据库,效果比较明显。

      1.4:当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,都会把对象放入session缓存中;

      1.5:session的缓存是由hibernate维护的,用户不能操作缓存内容;如果想操作缓存内容,必须通过hibernate提供的evict/clear方法操作

      1.6:缓存相关的方法(在什么情况下使用上面方法呢?批量操作情况下使用,如Session.flush();先与数据库同步,Session.clear();再清空一级缓存内容):

        session.flush();让一级缓存与数据库同步;

        session.evict();清空一级缓存中指定的对象;

        session.clear();清空一级缓存中所有的对象;

      1.7:面试题,不同的session是否会共享缓存数据?

          答:不会哦~~~

      1.8:list和iterator的区别?

        (1)list查询:

          答: 一次性把所有的记录都查询出来了;会放入缓存,不会从缓存中取数据;

        (2)iterate(N+1次查询):

          答: N表示所有的记录总数,即会发送一条语句查询所有的记录的主键,这是第一条查询语句,再根据每一个主键取数据库查询,这是根据第一次查询的条数进行N次查询操作;会放入缓存,也会从缓存中取出数据;


    2:Hibernate的懒加载:

      2.1:懒加载概念:当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性。

         使用懒加载的目的,是提高程序执行效率。

      2.2:查询操作:get()方法/load()方法

        (1)get()方法,及时加载。及时查询操作;只要调用get方法立刻向数据库查询。

        (2)load()方法,默认懒加载,即在使用数据的时候,才向数据库发送查询的sql语句。session关闭以后,不可以使用懒加载。

    #懒加载默认为true,即为懒加载,可以改为非懒加载。即lazy="false"
    #lazy="false" 关闭懒加载
    #lazy="true"使用懒加载
    #lazy="extra"在真正使用数据的时候才向数据库发送查询的sql语句。集合属性懒加载的时候提升效率。如果调用集合的size()/isEmpty()方法只是统计,不真正查询数据。
    <class name="类名称" table="数据表名称" lazy="false"> ...... </class>

       2.3:懒加载异常:

        Session关闭后,不能使用懒加载数据,如果session关闭后,使用懒加载数据报错如:

    org.hibernate.LazyInitializationException: could not initialize proxy - no Session
        at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
        at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
        at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
        at com.bie.lesson05.Dept_$$_javassist_1.getDeptName(Dept_$$_javassist_1.java)
        at com.bie.lesson05.ManyToManyTest.lazyTest(ManyToManyTest.java:241)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
        at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
        at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

        如何解决session关闭后不能使用懒加载加载数据的问题:

          方式一:可以先在关闭session之前使用一下数据,这样关闭以后就可以使用此数据了。如Dept.getDeptName();

          方式二(推荐):强迫代理对象初始化操作:Hibernate.initialize(对象);

          方式三:关闭懒加载(lazy="false");

          方式四(推荐):在使用数据之后再关闭session;


     3:二级缓存:

    Hibernate提供的缓存

    有一级缓存、二级缓存。 目的是为了减少对数据库的访问次数,提升程序执行效率!

     

    一级缓存:

    基于Session的缓存,缓存内容只在当前session有效,session关闭,缓存内容失效!

    特点:

    作用范围较小! 缓存的事件短。

    缓存效果不明显。

      3.1:二级缓存概述:

      二级缓存:

        Hibernate提供了基于应用程序级别的缓存即为二级缓存,可以跨多个session,即不同的session都可以访问缓存数据。 这个缓存也叫二级缓存。

        Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码。

        如果用户觉得hibernate提供的框架框架不好用,自己可以换其他的缓存框架或自己实现缓存框架都可以。  

      3.2:查看hibernate.properties配置文件,二级缓存如何配置?

    ##########################
    
    ### Second-level Cache ###
    
    ##########################
    
    #hibernate.cache.use_second_level_cache false【二级缓存默认不开启,需要手动开启】
    
    #hibernate.cache.use_query_cache true      【开启查询缓存】
    
     
    ## choose a cache implementation 【二级缓存框架的实现】
    
     
    #hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider
    
    #hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider
    
    hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider 默认实现
    
    #hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider
    
    #hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider
    
    #hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider

      3.3:二级缓存,使用步骤:

      1) 开启二级缓存;

      2)指定缓存框架;

      3)指定那些类加入二级缓存;

      4)测试;

    <!--****************** 【二级缓存配置】****************** -->
    <!-- a.  开启二级缓存 -->
    <property name="hibernate.cache.use_second_level_cache">true</property>
    <!-- b. 指定使用哪一个缓存框架(默认提供的) -->
    <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
    <!-- 开启查询缓存 -->
    <property name="hibernate.cache.use_query_cache">true</property>
    <!-- c. 指定哪一些类,需要加入二级缓存 -->
    <class-cache usage="read-write" class="com.bie.lesson11.Dept"/>
    <class-cache usage="read-only" class="com.bie.lesson11.Employee"/>
    <!-- 集合缓存[集合缓存的元素对象,也加加入二级缓存] -->
    <collection-cache usage="read-write" collection="com.bie.lesson11.Dept.emps"/>
            

       3.4:缓存策略:

    <class-cache usage="read-only"/>     放入二级缓存的对象,只读; 
    <class-cache usage="nonstrict-read-write"/>  非严格的读写
    <class-cache usage="read-write"/>    读写; 放入二级缓存的对象可以读、写;
    <class-cache usage="transactional"/>   (基于事务的策略)
  • 相关阅读:
    运算符的优先级
    运算符
    值类型与引用类型的区别
    进制转换
    Java总结第二期
    Java总结第一期
    库存管理系统
    MyBank后感
    day72
    day71
  • 原文地址:https://www.cnblogs.com/biehongli/p/6596700.html
Copyright © 2020-2023  润新知