课程咨询 :186 8716 1620      qq:2066486918

昆明Java培训 > 达内新闻 > Hibernate中的二级缓存
  • Hibernate中的二级缓存

    发布:昆明Java培训      来源:达内新闻      时间:2016-10-24

  • 昆明达内Java培训的老师今天给大家讲Hibernate——二级缓存

    一、Hibernate二级缓存

    1.Hibernate二级缓存是SessionFactory级别的缓存。

    2.二级缓存分为两类:

    (1)Hibernate内置二级缓存

    (2)外置缓存,可配置的,可插拨的,外置缓存中的数据是数据库数据的复制。

    3.二级缓存的并发访问策略

    (1)两个并发的事务同时访问持久层的缓存的相同数据时,也有可能出现并发问题。

    (2)二级缓存可以设定以下4中并发访问策略,每一种对应一种事务隔离级别。

    非严格读写(Nonstrict-read-write):不保证缓存与数据库中数据的一致性。对应Read UnCommited事务隔离级别。

    读写型(Read-write):提供Read Commited级别的事务隔离级别。

    事务型(Transactional):对应Repeatable Read级别的事务隔离级别。

    只读型(Read-Only):提供Serializable级别的数据隔离级别。

    4.Hibernate二级缓存是进程或集群范围内的缓存。是可配置的的插件。这里以Ehcache为例。不支持事务型的并发访问策略。

    5.配置Ehcache

    (1)添加Jar包

    (2)在Hibernate配置文件中启用二级缓存并指定适配的缓存适配器。

    在<session-factory>元素内添加:

    <property ame="cache.use_second_level_cache">true</property>

    <property ame="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

    (3)在Hibernate配置文件中配置需要使用二级缓存的持久化类,并设置它的二级缓存的并发访问策略。如:

    <class-cache class="com.solverpeng.hql.Department" usage="read-write"/>

    需要注意的是:<session-factory>元素内子元素的顺序:property*, mapping*, (class-cache|collection-cache)*, event*, listener*,class-cache元素必须位于mapping节点后。

    (4)或者也可以在hbm文件中配置,如:

    <hibernate-mapping>

    <class name="com.solverpeng.hql.Employee" table="employee" schema="hibernate">

    <cache usage="read-write"/>

    <id name="empId" column="emp_id"/>

    <property name="empName" column="emp_name"/>

    <property name="salary" column="salary"/>

    <many-to-one name="dept" class="com.solverpeng.hql.Department">

    <column ame="dept_id_fk" not-null="true"/>

    </many-to-one>

    </class>

    </hibernate-mapping>

    6.测试Hibernate二级缓存

    (1)查询单个对象缓存

    @Test

    public void testSecondCache() {

    Employee o = (Employee) session.get(Employee.class, 6);

    System.out.println(o);

    transaction.commit();

    session.close();

    session = factory.openSession();

    transaction = session.beginTransaction();

    Employee o1 = (Employee) session.get(Employee.class, 6);

    System.out.println(o1);

    }

    查询同一个对象两次,中间关闭Session再开启。

    没有配置二级缓存:

    Hibernate:

    select

    employee0_.emp_id as emp1_1_0_,

    employee0_.emp_name as emp2_1_0_,

    employee0_.salary as salary3_1_0_,

    employee0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee employee0_

    where

    employee0_.emp_id=?

    com.solverpeng.hql.Employee@40dd58f3

    Hibernate:

    select

    employee0_.emp_id as emp1_1_0_,

    employee0_.emp_name as emp2_1_0_,

    employee0_.salary as salary3_1_0_,

    employee0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee employee0_

    where

    employee0_.emp_id=?

    com.solverpeng.hql.Employee@40dd58f3

    结果:

    发送了2条SQL语句。

    配置二级缓存后(可以在Hibernate配置文件中配置,也可以在Employee hbm配置文件中配置):

    Hibernate:

    select

    employee0_.emp_id as emp1_1_0_,

    employee0_.emp_name as emp2_1_0_,

    employee0_.salary as salary3_1_0_,

    employee0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee employee0_

    where

    employee0_.emp_id=?

    com.solverpeng.hql.Employee@40dd58f3

    com.solverpeng.hql.Employee@40dd58f3

    结果:

    只发送了1条SQL语句。

    (2)集合缓存

    @Test

    public void testCollectionSecondLevelCache() {

    Department department = (Department) session.get(Department.class, 6);

    System.out.println(department.getDeptName());

    System.out.println(department.getEmps().size());

    transaction.commit();

    session.close();

    session = factory.openSession();

    transaction = session.beginTransaction();

    Department department2 = (Department) session.get(Department.class, 6);

    System.out.println(department2.getDeptName());

    System.out.println(department2.getEmps().size());

    }

    在没有配置二级缓存的情况下:

    Hibernate:

    select

    department0_.dept_id as dept1_0_0_,

    department0_.dept_name as dept2_0_0_

    from

    hibernate.department department0_

    where

    department0_.dept_id=?

    dept-aa

    Hibernate:

    select

    emps0_.dept_id_fk as dept4_0_1_,

    emps0_.emp_id as emp1_1_1_,

    emps0_.emp_id as emp1_1_0_,

    emps0_.emp_name as emp2_1_0_,

    emps0_.salary as salary3_1_0_,

    emps0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee emps0_

    where

    emps0_.dept_id_fk=?

    3

    Hibernate:

    select

    department0_.dept_id as dept1_0_0_,

    department0_.dept_name as dept2_0_0_

    from

    hibernate.department department0_

    where

    department0_.dept_id=?

    dept-aa

    Hibernate:

    select

    emps0_.dept_id_fk as dept4_0_1_,

    emps0_.emp_id as emp1_1_1_,

    emps0_.emp_id as emp1_1_0_,

    emps0_.emp_name as emp2_1_0_,

    emps0_.salary as salary3_1_0_,

    emps0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee emps0_

    where

    emps0_.dept_id_fk=?

    3

    结果:

    查询了两次Department,两次Employee

    只配置Department二级缓存:

    <class-cache class="com.solverpeng.hql.Department" usage="read-write"/>

    Hibernate:

    select

    department0_.dept_id as dept1_0_0_,

    department0_.dept_name as dept2_0_0_

    from

    hibernate.department department0_

    where

    department0_.dept_id=?

    dept-aa

    Hibernate:

    select

    emps0_.dept_id_fk as dept4_0_1_,

    emps0_.emp_id as emp1_1_1_,

    emps0_.emp_id as emp1_1_0_,

    emps0_.emp_name as emp2_1_0_,

    emps0_.salary as salary3_1_0_,

    emps0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee emps0_

    where

    emps0_.dept_id_fk=?

    3

    dept-aa

    Hibernate:

    select

    emps0_.dept_id_fk as dept4_0_1_,

    emps0_.emp_id as emp1_1_1_,

    emps0_.emp_id as emp1_1_0_,

    emps0_.emp_name as emp2_1_0_,

    emps0_.salary as salary3_1_0_,

    emps0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee emps0_

    where

    emps0_.dept_id_fk=?

    3

    结果:

    只查询了一次Department,2次Employee。

    说明:

    开启Department二级缓存后,会对Department进行缓存,而与其关联的emps不会进行缓存。

    配置Department二级缓存,同时配置关联的emps缓存。

    <class-cache class="com.solverpeng.hql.Department" usage="read-write"/>

    <collection-cache collection="com.solverpeng.hql.Department.emps" usage="read-write"/>

    Hibernate:

    select

    department0_.dept_id as dept1_0_0_,

    department0_.dept_name as dept2_0_0_

    from

    hibernate.department department0_

    where

    department0_.dept_id=?

    dept-aa

    Hibernate:

    select

    emps0_.dept_id_fk as dept4_0_1_,

    emps0_.emp_id as emp1_1_1_,

    emps0_.emp_id as emp1_1_0_,

    emps0_.emp_name as emp2_1_0_,

    emps0_.salary as salary3_1_0_,

    emps0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee emps0_

    where

    emps0_.dept_id_fk=?

    3

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

    dept-aa

    Hibernate:

    select

    employee0_.emp_id as emp1_1_0_,

    employee0_.emp_name as emp2_1_0_,

    employee0_.salary as salary3_1_0_,

    employee0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee employee0_

    where

    employee0_.emp_id=?

    Hibernate:

    select

    employee0_.emp_id as emp1_1_0_,

    employee0_.emp_name as emp2_1_0_,

    employee0_.salary as salary3_1_0_,

    employee0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee employee0_

    where

    employee0_.emp_id=?

    Hibernate:

    select

    employee0_.emp_id as emp1_1_0_,

    employee0_.emp_name as emp2_1_0_,

    employee0_.salary as salary3_1_0_,

    employee0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee employee0_

    where

    employee0_.emp_id=?

    3

    结果:

    发送了更多的查询Employee的SQL。

    说明:

    开启集合的二级缓存后,此时会缓存集合中对象的id,而不会对集合中的对象进行缓存。若想缓存,需要关联的集合中的对象也开启二级缓存。如:

    <class-cache class="com.solverpeng.hql.Department" usage="read-write"/>

    <collection-cache collection="com.solverpeng.hql.Department.emps" usage="read-write"/>

    <class-cache class="com.solverpeng.hql.Employee" usage="read-write"/>

    Hibernate:

    select

    department0_.dept_id as dept1_0_0_,

    department0_.dept_name as dept2_0_0_

    from

    hibernate.department department0_

    where

    department0_.dept_id=?

    dept-aa

    Hibernate:

    select

    emps0_.dept_id_fk as dept4_0_1_,

    emps0_.emp_id as emp1_1_1_,

    emps0_.emp_id as emp1_1_0_,

    emps0_.emp_name as emp2_1_0_,

    emps0_.salary as salary3_1_0_,

    emps0_.dept_id_fk as dept4_1_0_

    from

    hibernate.employee emps0_

    where

    emps0_.dept_id_fk=?

    3

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

    dept-aa

    3

    结果:

    除Department外,关联的Employee也被缓存了。

    (3)查询缓存(针对HQL、QBC)

    在二级缓存开启的情况下,HQL、QBC也不能对查询进行缓存。

    @Test

    public void testQueryCache() {

    Query query = session.createQuery("from Employee ");

    List<Employee> list = query.list();

    System.out.println(list.size());

    List<Employee> emps2 = query.list();

    System.out.println(emps2.size());

    }

    Hibernate:

    select

    employee0_.emp_id as emp1_1_,

    employee0_.emp_name as emp2_1_,

    employee0_.salary as salary3_1_,

    employee0_.dept_id_fk as dept4_1_

    from

    hibernate.employee employee0_

    12

    Hibernate:

    select

    employee0_.emp_id as emp1_1_,

    employee0_.emp_name as emp2_1_,

    employee0_.salary as salary3_1_,

    employee0_.dept_id_fk as dept4_1_

    from

    hibernate.employee employee0_

    12

    开启查询缓存:

    在Hibernate配置文件中开启查询缓存

    若想启用查询缓存的查询语句,需要调用Query或Criteria的setCacheable()方法。

    查询缓存依赖于二级缓存

    <property ame="hibernate.cache.use_query_cache">true</property>

    @Test

    public void testQueryCache() {

    Query query = session.createQuery("from Employee ");

    query.setCacheable(true);

    List<Employee> list = query.list();

    System.out.println(list.size());

    List<Employee> emps2 = query.list();

    System.out.println(emps2.size());

    }

    Hibernate:

    select

    employee0_.emp_id as emp1_1_,

    employee0_.emp_name as emp2_1_,

    employee0_.salary as salary3_1_,

    employee0_.dept_id_fk as dept4_1_

    from

    hibernate.employee employee0_

    12

    12

    (4)时间戳缓存区域:时间戳缓存区存放了对于查询结果相关的表进行插入、更新或删除操作的时间戳。Hibernate通过时间戳缓存区来判定被缓存的查询结果是否过期。

    @Test

    public void testTimStampCache() {

    Query query = session.createQuery("from Employee ");

    query.setCacheable(true);

    List<Employee> list = query.list();

    System.out.println(list.size());

    Employee employee = (Employee) session.get(Employee.class, 6);

    employee.setEmpName("emp@@");

    List<Employee> emps2 = query.list();

    System.out.println(emps2.size());

    }

    Hibernate:

    select

    employee0_.emp_id as emp1_1_,

    employee0_.emp_name as emp2_1_,

    employee0_.salary as salary3_1_,

    employee0_.dept_id_fk as dept4_1_

    from

    hibernate.employee employee0_

    12

    Hibernate:

    update

    hibernate.employee

    set

    emp_name=?,

    salary=?,

    dept_id_fk=?

    where

    emp_id=?

    Hibernate:

    select

    employee0_.emp_id as emp1_1_,

    employee0_.emp_name as emp2_1_,

    employee0_.salary as salary3_1_,

    employee0_.dept_id_fk as dept4_1_

    from

    hibernate.employee employee0_

    12

    了解详情请登陆昆明达内Java培训官网(km.Java.tedu.cn)!

    推荐文章

上一篇:Java培训:Spring之AOP

下一篇:Hibernate中的ehcache.xml

最新开班日期  |  更多

Java--零基础全日制班

Java--零基础全日制班

开班日期:11/30

Java--零基础业余班

Java--零基础业余班

开班日期:11/30

Java--周末提升班

Java--周末提升班

开班日期:11/30

Java--零基础周末班

Java--零基础周末班

开班日期:11/30

  • 网址:http://km .java.tedu.cn      地址:昆明市官渡区春城路62号证券大厦附楼6楼
  • 课程培训电话:186 8716 1620      qq:2066486918    全国服务监督电话:400-827-0010
  • 服务邮箱 ts@tedu.cn
  • 2001-2016 达内国际公司(TARENA INTERNATIONAL,INC.) 版权所有 京ICP证08000853号-56