您的位置:首页 > 编程语言 > Java开发

Hibernate EHCache Second Level Cache Example

2016-06-04 00:00 731 查看
摘要: 了解过Hibernate都知道,Hibernate本身不提供二级缓存的实现,而是使用第三方的缓存产品,比如EHCache等等,这个实例就是讲讲hibernate和EHCache的整合。

1.项目目录结构



2.项目依赖

下面是pom.xml文件

[code=language-xml]<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>HibernateEHCacheSample</groupId>
<artifactId>HibernateEHCacheSample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>HibernateEHCacheSample</name>
<description />
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- Hibernate Core API -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.5.Final</version>
</dependency>
<!-- MySQL Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.5</version>
</dependency>
<!-- EHCache Core APIs -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.9</version>
</dependency>
<!-- Hibernate EHCache API -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.3.5.Final</version>
</dependency>
<!-- EHCache uses slf4j for logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<version>3.0</version>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>


3.配置缓存策略

3.1 Model类

这个实例中对这个类做缓存

[code=language-java]package com.lin.hibernate.model;

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 org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity
@Table(name="TB_NEWS")
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="news")
public class News {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "NEWS_ID")
private int id;

@Column(name="TITLE")
private String title;

@Column(name="CONTENT")
private String content;

public int getId() {
return id;
}

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

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

@Override
public String toString() {
return "News [id=" + id + ", title=" + title + ", content=" + content
+ "]";
}

}


3.2 EHCache配置文件

[code=language-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="news" maxEntriesLocalHeap="10000" eternal="false"
timeToIdleSeconds="5" timeToLiveSeconds="10">
<persistence strategy="localTempSwap" />
</cache>

<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>
</ehcache>

说明一下上面的一些配置项:

name:cache唯一标识
eternal:缓存是否永久有效
maxElementsInMemory:内存中最大缓存对象数
overflowToDisk(true,false):缓存对象达到最大数后,将缓存写到硬盘中
diskPersistent:硬盘持久化
timeToIdleSeconds:缓存清除时间
timeToLiveSeconds:缓存存活时间
memoryStoreEvictionPolicy:缓存清空策略
1.FIFO:first in first out 先讲先出
2.LFU: Less Frequently Used 一直以来最少被使用的
3.LRU:Least Recently Used 最近最少使用的

另外,需要说明下面几个:

1) diskStore:如果缓存超出配置规定的大小,就会存在磁盘哪个位置

2) defaultCache:这个是强制配置项,如果某些对象没有配置缓存策略,那么默认就是使用这个default配置

3) cache name=”news”:为News类配置的缓存策略

4)
配置org.hibernate.cache.internal.StandardQueryCache 和 org.hibernate.cache.spi.UpdateTimestampsCache,不然ehcache会有一些警告


4.Hibernate

4.1 hibernate.cfg.xml

[code=language-xml]<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration SYSTEM "classpath://org/hibernate/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/test</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>

<property name="hibernate.hbm2ddl.auto">update</property>

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

<!-- For singleton factory -->
<!-- <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
-->

<!-- enable second level cache and query cache -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="net.sf.ehcache.configurationResourceName">/ehcache.xml</property>

<mapping class="com.lin.hibernate.model.News" />
</session-factory>
</hibernate-configuration>

说明:

1) hibernate.cache.region.factory_class是hibernate配置二级缓存的工厂类,这里我们使
org.hibernate.cache.ehcache.EhCacheRegionFactory


如果想使用单例工厂,那么就用org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory


2) 如果使用的是Hibernate3,那么上面对应的两个类就应该是
net.sf.ehcache.hibernate.EhCacheRegionFactory
net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory


3) hibernate.cache.use_second_level_cache的只是boolean,表示是否开启二级缓存

4) hibernate.cache.use_query_cache表示是否开启查询缓存,如果不开启,那么HQL的查询结果将不会被缓存

5) net.sf.ehcache.configurationResourceName配置ehcache的配置文件位置,如果不配置,ehcache会默认认为classpath下 的ehcache.xml文件

4.2 HibernateUtil

[code=language-java]package com.lin.hibernate.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

private static SessionFactory sessionFactory;

private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
System.out.println("Hibernate Configuration loaded");

ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
System.out.println("Hibernate serviceRegistry created");

SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);

return sessionFactory;
}
catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
ex.printStackTrace();
throw new ExceptionInInitializerError(ex);
}
}

public static SessionFactory getSessionFactory() {
if(sessionFactory == null) sessionFactory = buildSessionFactory();
return sessionFactory;
}
}


5. 怎么知道二级缓存发挥了作用?

5.1 测试类

[code=language-java]package com.lin.hibernate.main;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.lin.hibernate.model.News;
import com.lin.hibernate.util.HibernateUtil;

public class HibernateEHCacheMain {

public static void main(String[] args) {

System.out.println("Temp Dir:"+System.getProperty("java.io.tmpdir"));

//Initialize Sessions
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();

//        News news = new News();
//        news.setTitle("Test EHcache");
//        news.setContent("This is a news...");
//        session.save(news);

News news = (News)session.get(News.class, 1);
System.out.println(news.toString());
session.evict(news);//清除了一级缓存
news = (News)session.get(News.class, 1);
System.out.println(news.toString());

//Release resources
transaction.commit();
sessionFactory.close();
}

}


5.2 没有二级缓存是怎么样

首先看没有二级缓存的情况,在hibernate.cfg.xml里面配置:

[code=language-xml]<!-- enable second level cache and query cache -->
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.use_query_cache">false</property>

上面关闭了二级缓存,运行测试类,控制打印:



一级缓存不存在news时,每查询一次news对象就执行依次sql

5.3 开启二级缓存

在hibernate.cfg.xml里面设置

[code=language-xml]<!-- enable second level cache and query cache -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>

控制台打印:



可以看到,当我们在清除一级缓存的时候,再次查询同样的对象,hibernate不会再次执行sql,而是从二级缓存里去读取

5.4 关于load和get

有时,配置了二级缓存却发现没有作用,应该看看使用的查询接口是load还是get

get:先从一级缓存中查询符合条件的对象,找不到则直接从数据库中查询,如果都查询不到则返回null;

load:先从一级缓存中查询符合条件的对象,找不到再在二级缓存中查询,如果还找不到就抛出异常;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java hibernate ehcache