Hibernate二级缓存

Hibernate第二级缓存是会话工厂的所有会话(Session)对象所使用的公共缓存。 如果您有来自会话工厂的多个会话(Session)对象,就可以操作会话工厂中的第二级缓存的数据。

SessionFactory类用于保存二级缓存数据。 它是所有会话对象的全局,默认情况下是不启用的。

不同厂商提供了二级缓存的实现。

  1. EH二级缓存
  2. OS二级缓存
  3. Swarm二级缓存
  4. JBoss二级缓存

每个实现提供不同的缓存使用功能。 有四种方法可以使用二级缓存。

  1. 只读:缓存将适用于只读操作。
  2. 非严格读写:缓存可用于读写,但一次只能读写。
  3. 读写:缓存将用于读写,可以同时使用。
  4. 事务处理:缓存将用于事务处理。
    缓存使用属性可以应用于hbm.xml文件中的类或集合级别。 下面给出了定义缓存使用情况的例子:
    <cache usage="read-only" />
    
    XML
    下面来看看看二级缓存实现和缓存使用情况。
实现只读非限制读写读写操作
EH二级缓存 Yes Yes Yes No
OS二级缓存 Yes Yes Yes No
Swarm二级缓存 Yes Yes No No
JBoss二级缓存 No No No Yes

使用EH缓存的二级缓存示例的额外步骤

1)在hibernate.cfg.xml文件中添加2个配置设置

<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>  
<property name="hibernate.cache.use_second_level_cache">true</property>
XML

2) 在hbm文件中添加缓存使用情况设置

<cache usage="read-only" />
XML

3) 创建ehcache.xml文件

<?xml version="1.0"?>  
<ehcache>  
    <defaultCache maxElementsInMemory="100"  eternal="true"/>  
</ehcache>
XML

Hibernate二级缓存示例

要通过下面示例了解二级缓存,我们需要创建一个Java项目:secondlevel, 其完整的目录结构如下所示 -

创建以下页面:

  1. Employee.java
  2. employee.hbm.xml
  3. hibernate.cfg.xml
  4. ehcache.xml
  5. MainTest.java

注意:在这里,我们假设,在MySQL数据库中有一个emp_cache2表并包含一些记录。

文件: Employee.java

package com.yiibai;

public class Employee {
    private int id;
    private String name;
    private float salary;

    public Employee() {
        super();
    }

    public Employee(String name, float salary) {
        super();
        this.name = name;
        this.salary = salary;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public float getSalary() {
        return salary;
    }

    public void setSalary(float salary) {
        this.salary = salary;
    }

}
Java

文件: employee.hbm.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
          "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.yiibai.Employee" table="emp_cache">
        <cache usage="read-only" />
        <id name="id">
            <generator class="native"></generator>
        </id>
        <property name="name"></property>
        <property name="salary"></property>
    </class>

</hibernate-mapping>
XML

在这里,我们使用只读(read-only)高速缓存来使用该类。缓存使用情况也可用于集合。

文件: hibernate.cfg.xml

XML

要实现二级缓存,我们需要在配置文件中定义cache.provider_class属性。

文件:ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
    monitoring="autodetect" dynamicConfig="true">

    <diskStore path="java.io.tmpdir/ehcache" />

    <defaultCache maxEntriesLocalHeap="10000" eternal="false"
        timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30"
        maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU" statistics="true">
        <persistence strategy="localTempSwap" />
    </defaultCache>

    <cache name="org.hibernate.cache.internal.StandardQueryCache"
        maxEntriesLocalHeap="5" eternal="false" timeToLiveSeconds="120">
        <persistence strategy="localTempSwap" />
    </cache>

    <cache name="org.hibernate.cache.spi.UpdateTimestampsCache"
        maxEntriesLocalHeap="5000" eternal="true">
        <persistence strategy="localTempSwap" />
    </cache>
    <cache name="com.yiibai.Employee" maxElementsInMemory="100"
        eternal="false" timeToIdleSeconds="5" timeToLiveSeconds="200" />
</ehcache>
XML

我们需要创建ehcache.xml文件来定义缓存属性。

defaultCache将用于所有持久化类。 我们还可以通过使用 cache 元素来明确定义持久化类。
eternal 如果我们指定eternal =“true”,则不需要定义timeToIdleSecondstimeToLiveSeconds属性,因为它将由hibernate内部处理。 指定eternal =“false”给程序员控制,但是我们需要定义timeToIdleSecondstimeToLiveSeconds属性
timeToIdleSeconds它定义了二级缓存中对象可以空闲多少秒。
timeToLiveSeconds它定义了在第二级缓存中对象可以存储多少秒,无论它是否空闲。

文件:MainTest.java

package com.yiibai;

import org.hibernate.*;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.*;
import org.hibernate.stat.Statistics;

public class MainTest {
    public static void main(String[] args) {
        // 在5.1.0版本汇总,hibernate则采用如下新方式获取:
        // 1. 配置类型安全的准服务注册类,这是当前应用的单例对象,不作修改,所以声明为final
        // 在configure("cfg/hibernate.cfg.xml")方法中,如果不指定资源路径,默认在类路径下寻找名为hibernate.cfg.xml的文件
        final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
                .configure("hibernate.cfg.xml").build();
        // 2. 根据服务注册类创建一个元数据资源集,同时构建元数据并生成应用一般唯一的的session工厂
        SessionFactory sessionFactory = new MetadataSources(registry)
                .buildMetadata().buildSessionFactory();

        /**** 上面是配置准备,下面开始我们的数据库操作 ******/
        Session session = sessionFactory.openSession();// 从会话工厂获取一个session

        // creating transaction object
        Transaction tx = session.beginTransaction();

        Statistics stats = sessionFactory.getStatistics();
        System.out.println("Stats enabled="+stats.isStatisticsEnabled());

        stats.setStatisticsEnabled(true);
        System.out.println("Stats enabled="+stats.isStatisticsEnabled());

        session.save(new Employee("苏小牛", 12000));
        session.save(new Employee("库日天", 19000));

        Session session1 = sessionFactory.openSession();
        Employee emp1 = (Employee) session1.load(Employee.class, 1);
        System.out.println(emp1.getId() + " " + emp1.getName() + " "
                + emp1.getSalary());
        session1.close();

        //再次查询ID=1的员工信息,因为使用了缓存,这里不会再发出查询语句...
        Session session11 = sessionFactory.openSession();
        Employee emp11 = (Employee) session11.load(Employee.class, 1);
        System.out.println(emp11.getId() + " " + emp11.getName() + " "
                + emp11.getSalary());
        session11.close();


        Session session2 = sessionFactory.openSession();
        Employee emp2 = (Employee) session2.load(Employee.class, 2);
        System.out.println(emp2.getId() + " " + emp2.getName() + " "
                + emp2.getSalary());
        session2.close();

        tx.commit();
        session.close();
        sessionFactory.close();
    }
}
Java

我们可以看到,hibernate不会发出两次查询。 如果不使用二级缓存,hibernate将会发出两次查询,因为这两个查询都使用不同的会话对象。

运行实例

首先运行 MainTest.java 插入数据,然后再读取数据。
执行 MainTest.java 得到以下结果,

log4j:WARN No appenders could be found for logger (org.jboss.logging).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Wed Mar 29 21:38:06 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Stats enabled=false
Stats enabled=true
Hibernate: insert into emp_cache (name, salary) values (?, ?)
Hibernate: insert into emp_cache (name, salary) values (?, ?)
Hibernate: select employee0_.id as id1_0_0_, employee0_.name as name2_0_0_, employee0_.salary as salary3_0_0_ from emp_cache employee0_ where employee0_.id=?
Wed Mar 29 21:38:08 CST 2017 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
1 苏小牛 12000.0
1 苏小牛 12000.0
Hibernate: select employee0_.id as id1_0_0_, employee0_.name as name2_0_0_, employee0_.salary as salary3_0_0_ from emp_cache employee0_ where employee0_.id=?
2 库日天 19000.0
Shell
 
原文地址:https://www.cnblogs.com/borter/p/9522215.html