hibernate ehcache 配置指导

来源:互联网 发布:数据库视频百度云 编辑:程序博客网 时间:2024/06/05 00:34

缓存由ORM框架提供以便用户可以获得更快速的访问速度,同时框架本身也减少了数据库查询操作。hibernate同样在两个层上提供了缓存的功能。

一级缓存:这是在session范围内默认使用的,了解更多可以读这篇文章。

二级缓存:这是在一级缓存之上的缓存,在session factory 范围内有效。

在这篇文章中,我将给出使用ehcache在hibernate配置二级缓存的例子。


这篇文章的结构:

二级缓存是如何工作的

关于ehcache

配置ehcache

配置实体对象

查询缓存

应用例子

源码下载

二级缓存是如何工作的

1、当hibernate Session试着加载实体的时候,会从一级缓存中获取对象的复制(与特定的hibernate Session相关连)
2、如果在一级缓存中存在实体的复制,将会把实体结果返回。
3、如果在一级缓存中不存在缓存的实体,二级缓存会查找是不是有缓存的实体。
4、如果二级缓存中有缓存的实体,将会把实体的结果返回。但是,在返回实体之前,它将会把结果存储到一级缓存中去,下次调用时可以直接从一级缓存中获取相应的结果,这样就没有必要再想二级缓存中获取。
5、如果在一级缓存和二级缓存中都没有找到相应的实体,那么数据库查询语句将会执行,在返回结果之前,实体将会被存储在一二级缓存中。
6、如果通过hibernate操作修改已经完成,对于修改的实体二级缓存会完成相应的验证。
7、如果用户或者进程直接在数据库中做了修改,二级缓存不能更新自己直到timeToLiveSeconds时间结束。在这种情况下最好将所有的缓存失效并让hibernate再一次建立自己的缓存,你可以使用下边的代码片段失效整个hibernate的二级缓存。

关于更多二级缓存是如何工作的,可以参考这篇文章。

关于ehcache

Terracotta  ehcache是一个流行的开源的Java缓存,可以被用在hibernate的二级缓存中,ehcache也可以被当做独立的二级缓存使用,或者为集群配置提供二级缓存。hibernate可以使用ehcache的库,如果你想要ehcache的某一个具体的版本,可以访问网址
http://www.terracotta.org/products/enterprise-ehcache
ehcache2.0的maven依赖如下:
<dependency>    <groupId>net.sf.ehcache</groupId>    <artifactId>ehcache</artifactId>    <version>[2.0.0]</version>    <type>pom</type></dependency>

配置ehcache

为了配置ehcache,你需要做下边两个步骤的事情:
1、为二级缓存配置hibernate
2、制定二级缓存的提供者
hibernate3.3以上的版本
<property key="hibernate.cache.use_second_level_cache">true</property><property name="hibernate.cache.region.factory_class">net.sf.ehcache.hibernate.EhCacheRegionFactory</property>

hibernate3.2和以下版本
<property key="hibernate.cache.use_second_level_cache">true</property><property name="hibernate.cache.region.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property>

配置实体对象

可以使用两种方式
(1)如果使用hbm.xml文件,使用下边的配置
<class name="com.application.entity.DepartmentEntity" table="...">    <cache usage="read-write"/></class>

(2)如果使用注解,是用下边这些注解
@Entity@Cache(usage=CacheConcurrencyStrategy.READ_ONLY,region="department")public class DepartmentEntity implements Serializable{    //code}

对于上边这两种方式,缓存策略可以是下边的类型:
none:不会有缓存发生
read-only:如果你的应用需要读而不是修改,持久类的实例上可以使用read-only缓存
read-write:如果你的缓存需要更新数据,一个read-write缓存是很合适的。
nonstrict-read-write:如果你的应用只在特定的情况下更新数据(例如:一个极特殊的情况,两个事物同时更新数据),并且没有严格是事务独立要求,nonstrict-read-write或许就是合适的选择。
transactional:事务缓存策略为为所有的事务缓存提供者提供支持,比如一个缓存可以仅仅在JTA中使用,你必须指定hibernate.transaction.manager_lookup_class.

查询缓存

你可是使用在hbm.xml中配置如下的语句使查询缓存生效
<property key="hibernate.cache.use_query_cache">true</property>

在你的代码中定义的查询上增加方法setCacheable(true),这样就可以缓存了。
sessionFactory.getCurrentSession().createQuery("...").setCacheable(true).list();

默认情况下,ehcache会为你配置的需要缓存每一个实体划分出不同的缓存区域。你可以在ehcache.xml中增加配置来改变这个默认的区域。
<property name="net.sf.ehcache.configurationResourceName">/ehcache.xml</property>

使用下边的配置覆盖默认的配置
<cache    name="com.somecompany.someproject.domain.Country"    maxElementsInMemory="10000"    eternal="false"    timeToIdleSeconds="300"    timeToLiveSeconds="600"    overflowToDisk="true"/>

在ehcache.xml中需要注意:如果eternal="true"那么我们不需要写 timeToIdealSeconds, timeToLiveSeconds,hibernate会处理这些值,如果你想人为的给定缓存的值最好还是使用上边的那种配置方式,这样我们就可以手动的将值指定 timeToIdealSeconds,timeToLiveSeconds 。
timeToIdealSeconds=”seconds”意味着,如果对象在全局缓存中是理想的,在全局中使用的类或者对象将会等待超过我们设置的timeToIdealSeconds 时间值将缓存的值删除。
timeToLiveSeconds=”seconds” 意味着,其他的session或者类使用不是使用这个对象,超过这个时间,hibernate将会从全局缓存中将它删除。

例子

在我们的应用例子中,我有一个DepartmentEntity,在这上边使用ehcache的二级缓存,让我们一步一步操作这个事情
1) hibernate.cfg.xml:
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration>    <session-factory>        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatedemo</property>        <property name="hibernate.connection.password">password</property>        <property name="hibernate.connection.username">root</property>        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>        <property name="show_sql">true</property>        <property name="hbm2ddl.auto">create</property>        <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>        <mapping class="hibernate.test.dto.DepartmentEntity"></mapping>    </session-factory></hibernate-configuration>

2) DepartmentEntity.java:
package hibernate.test.dto; import java.io.Serializable; import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;import javax.persistence.UniqueConstraint; import org.hibernate.annotations.Cache;import org.hibernate.annotations.CacheConcurrencyStrategy; @Entity (name = "dept")@Table(name = "DEPARTMENT", uniqueConstraints = {        @UniqueConstraint(columnNames = "ID"),        @UniqueConstraint(columnNames = "NAME") })         @Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="department") public class DepartmentEntity implements Serializable {         private static final long serialVersionUID = 1L;     @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)    @Column(name = "ID", unique = true, nullable = false)    private Integer id;         @Column(name = "NAME", unique = true, nullable = false, length = 100)    private String name;     public Integer getId() {        return id;    }     public void setId(Integer id) {        this.id = id;    }     public String getName() {        return name;    }     public void setName(String name) {        this.name = name;    }}

3) HibernateUtil.java:
package hibernate.test; import java.io.File; import org.hibernate.SessionFactory;import org.hibernate.cfg.AnnotationConfiguration; public class HibernateUtil{    private static final SessionFactory sessionFactory = buildSessionFactory();          private static SessionFactory buildSessionFactory()    {        try        {            // Create the SessionFactory from hibernate.cfg.xml            return new AnnotationConfiguration().configure(new File("hibernate.cgf.xml")).buildSessionFactory();        }        catch (Throwable ex) {            // Make sure you log the exception, as it might be swallowed            System.err.println("Initial SessionFactory creation failed." + ex);            throw new ExceptionInInitializerError(ex);        }    }      public static SessionFactory getSessionFactory() {        return sessionFactory;    }      public static void shutdown() {        // Close caches and connection pools        getSessionFactory().close();    }}

4) TestHibernateEhcache.java:
public class TestHibernateEhcache{      public static void main(String[] args)    {        storeData();                 try        {            //Open the hibernate session            Session session = HibernateUtil.getSessionFactory().openSession();            session.beginTransaction();                         //fetch the department entity from database first time            DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));            System.out.println(department.getName());                         //fetch the department entity again; Fetched from first level cache            department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));            System.out.println(department.getName());                         //Let's close the session            session.getTransaction().commit();            session.close();                         //Try to get department in new session            Session anotherSession = HibernateUtil.getSessionFactory().openSession();            anotherSession.beginTransaction();                         //Here entity is already in second level cache so no database query will be hit            department = (DepartmentEntity) anotherSession.load(DepartmentEntity.class, new Integer(1));            System.out.println(department.getName());                         anotherSession.getTransaction().commit();            anotherSession.close();        }        finally        {            System.out.println(HibernateUtil.getSessionFactory().getStatistics().getEntityFetchCount()); //Prints 1            System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount()); //Prints 1                         HibernateUtil.shutdown();        }    }         private static void storeData()    {        Session session = HibernateUtil.getSessionFactory().openSession();        session.beginTransaction();                 DepartmentEntity department = new DepartmentEntity();        department.setName("Human Resource");                 session.save(department);        session.getTransaction().commit();    }} Output: Hibernate: insert into DEPARTMENT (NAME) values (?)Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?Human ResourceHuman ResourceHuman Resource11

在上边的输出结果中,我们可以看到,第一次department是从数据库中获取,下边两次是从缓存中获取,最后一次是从二级缓存中获取。
源码下载
0 0