Hibernate 使用ehcache配置二级缓存

Hibernate 使用ehcache配置二级缓存

 Hibernate包括两个级别的缓存:
  1、一级缓存:默认总是启用的session级别的。
  2、二级缓存:可选的SessionFactory级别的。二级缓存默认情况下是关闭的,如果需要使用打开。使用二级缓存需要借助第三方工具:ehcache  redis 等。
  

什么样的数据适合存放到第二级缓存中?
1 很少被修改的数据
2 不是很重要的数据,允许出现偶尔并发的数据
3 不会被并发访问的数据
4 参考数据,指的是供应用参考的常量数据,它的实例数目有限,它的实例会被许多其他类的实例引用,实例极少或者从来不会被修改。


不适合存放到第二级缓存的数据?
1 经常被修改的数据
2 财务数据,绝对不允许出现并发
3 与其他应用共享的数据。



使用EhCache配置二级缓存:

1、需要导入的jar包




2、需要在主配置文件中配置
<!-- 配置二级缓存 -->
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
<!-- 使用二级缓存管理哪个类的数据,以何种权限实现管理 -->
<class-cache usage="read-write" class="cn.sz.pojo.User" />
<!-- 集合缓存[集合缓存的元素对象,也要加入二级缓存] -->
<collection-cache usage="nonstrict-read-write" collection="cn.sz.pojo.User.orderss" />


3、需要 ehcache.xml文件


下面是测试案例:


 本案例使用的hibernate版本为  hibernate-release-5.2.10.Final 。 为了测试,本案例在mysql数据库中创建了一个db数据库。 示例描述一个案例,在网上购物系统中一个用户可以有多个订单,所以用户和订单属于一对多关系,下面进行测试:
 

项目结构:



ehcache.xml缓存文件放在src下面(本人忘记截图了)。

lib目录下则是hibernate5需要的jar包(注需要将jar加载到项目中:选中jar包右键 --》BuildPath--》Add to Build Path)


log4j.properties为日志配置文件(需要加载配置junit),此项目可以不需要日志,使用日志只是为了观察方便。
注:junit配置可以参考 http://blog.csdn.net/benxiaohai888/article/details/78231911

由于在主配置文件配置了字段创建数据表的配置,所以第一次加载时就会自动创建数据表

配置的代码:

<!-- 自动生成数据表(数据表的生成方式) -->
<property name="hbm2ddl.auto">update</property>


示例代码:

1、主配置文件 hibernate.hbm.xml


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<session-factory>
		<!--配置一:数据库连接信息 -->
		<!-- 数据库驱动 -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<!-- 数据库URL -->
		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/db?characterEncoding=utf8</property>
		<!--数据库用户名, -->
		<property name="hibernate.connection.username">root</property>
		<!--数据库密码 -->
		<property name="hibernate.connection.password"></property>

		<!--配置二:数据库方言配置,配置数据库方言的作用是屏蔽数据库的差异,换句话说是使hibernate框架知道 要与哪种数据库取得联系 -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>

		<!-- <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> -->

		<!--配置三:其它配置 (这些配置可选) -->


		<!-- 配置二级缓存 -->
		<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>

		<!-- 是否在控制台显示sql语句 -->
		<property name="hibernate.show_sql">true</property>
		<!--是否格式化删除sql语句 -->
		<property name="hibernate.format_sql">true</property>
		<!-- 自动生成数据表(数据表的生成方式) -->
		<property name="hbm2ddl.auto">update</property>
		<!-- 将session绑定到当前线程 -->
		<property name="hibernate.current_session_context_class">thread</property>
		<!-- 设置事务的隔离级别 -->
		<property name="hibernate.connection.isolation">4</property>

		<!-- 配置四:映射配置 -->
		<!-- 基于注解的配置方式 -->
		<mapping class="cn.sz.pojo.User" />
		<mapping class="cn.sz.pojo.Orders" />

		<!-- 使用二级缓存管理哪个类的数据,以何种权限实现管理 -->
		<class-cache usage="read-write" class="cn.sz.pojo.User" />
		<!-- 集合缓存[集合缓存的元素对象,也要加入二级缓存] -->
		<collection-cache usage="nonstrict-read-write"
			collection="cn.sz.pojo.User.orderss" />
	</session-factory>
</hibernate-configuration>
	


2、ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <diskStore path="d:/hibernateCache"/>
    <defaultCache
        maxElementsInMemory="10"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"/>
        
    <cache name="cn.sz.pojo.User"
        maxElementsInMemory="10"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"/>
        
</ehcache>



3、log4j.properties(日志文件)
log4j.rootLogger=DEBUG,console,FILE
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.threshold=INFO
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%5p] - %c -%F(%L) -%m%n
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.maxBackupIndex=100
##log4j.appender.FILE=org.apache.log4j.DailyRollingFileAppender 
log4j.appender.FILE.Append=true
log4j.appender.FILE.File=c:/error1.log
log4j.appender.FILE.Threshold=INFO
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%5p] - %c -%F(%L) -%m%n
log4j.appender.FILE.MaxFileSize=1MB



4、HibernateUtil.java (获取session工具类)
package cn.sz.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
	public static Session getSession() {
		Session session = null;
		// 创建一个读取主配置文件的对象
		Configuration cfg = new Configuration();
		// 读取主配置文件
		// cfg.configure("hibernate.cfg.xml");如果读取的主配置文件时默认的名字则可以省略参数
		cfg.configure();
		// 创建SessionFactory
		SessionFactory factory = cfg.buildSessionFactory();
		// 打开session
		// 我们在主配置中已经将session绑定到线程中,所以可以从线程中取出session
		// 不从线程中取出session,则可以使用 factory.openSession(); 方式获得session
		session = factory.getCurrentSession();
		return session;

	}

}



5、订单实体类 Orders.java
package cn.sz.pojo;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "h_orders")
public class Orders {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer ordersId;
	private String ordersName;

	// 一对多关系(用户和订单)
	@ManyToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "userId")
	private User user;

	public Integer getOrdersId() {
		return ordersId;
	}

	public void setOrdersId(Integer ordersId) {
		this.ordersId = ordersId;
	}

	public String getOrdersName() {
		return ordersName;
	}

	public void setOrdersName(String ordersName) {
		this.ordersName = ordersName;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	@Override
	public String toString() {
		return "Orders [ordersId=" + ordersId + ", ordersName=" + ordersName + "]";
	}

}



6、用户实体类 User.java
package cn.sz.pojo;

import java.util.Date;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "h_user")
public class User {
	// 基于外键的方式时,使用的配置(一对一关系)

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer userId;

	private String userName;
	private Date birthday;

	// 一对多关系(用户和订单),添加cascade配置并不能实现一的一方维护关系
	@OneToMany(targetEntity = Orders.class, mappedBy = "user", cascade = CascadeType.ALL)
	private Set<Orders> orderss;

	public User() {
	}

	public User(String userName, Date birthday) {
		this.userName = userName;
		this.birthday = birthday;
	}

	public Integer getUserId() {
		return userId;
	}

	public void setUserId(Integer userId) {
		this.userId = userId;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public Set<Orders> getOrderss() {
		return orderss;
	}

	public void setOrderss(Set<Orders> orderss) {
		this.orderss = orderss;
	}

	@Override
	public String toString() {
		return "User [userId=" + userId + ", userName=" + userName + ", birthday=" + birthday + "]";
	}

}



7、测试类

package cn.sz.test;

import org.hibernate.Session;
import org.junit.Test;

import cn.sz.pojo.User;
import cn.sz.utils.HibernateUtil;

public class EhcacheTest {
	@Test
	public void test1() {
		// 查询id为1的用户
		Session session1 = HibernateUtil.getSession();
		session1.beginTransaction();
		User u1 = session1.get(User.class, 1);
		System.out.println(u1);
		session1.getTransaction().commit();
		session1.close();

		// 查询id为1的用户
		Session session2 = HibernateUtil.getSession();
		session2.beginTransaction();
		User u2 = session2.get(User.class, 1);
		System.out.println(u2);
		session2.getTransaction().commit();
		session2.close();
	}
}



测试结果:




我们发现我们用session1查询id为1的用户信息,查询完成之后我们关闭session1,当我们使用session2 查询id为1 用户时,并没有向数据库发送查询语句,而是直接输出信息。

总结:当session1进行查询操作时,当开启了二级缓存时,首先到二级缓存中查找,如果没有找到,才会向数据库发送sql语句,将结果返回保存在二级缓存,放入一级缓存;当session2  再次进行相同的查询时,先从二级缓存找,此时能找到,所以就不会向数据库发送sql,而是直接 由二级缓存返回数据 。


补充知识点:


ehcache.xml文件配置详解:

    name:缓存名称。
    maxElementsInMemory:缓存最大个数。
    eternal:对象是否永久有效,一但设置了,timeout将不起作用。
    timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
    timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
   overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
   diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
   maxElementsOnDisk:硬盘最大缓存个数。
   diskPersistent:是否缓存虚拟机重启期数据 
   diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
   memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
   clearOnFlush:内存数量最大时是否清除。 
   注:   <diskStore path="d:/hibernateCache" />  就是在缓存存储在 d盘下的hibernateCache目录。


缓存usage事务隔离机制:

 Usage提供缓存对象的事务隔离机制有如下几种:
  (NONE, READ_ONLY, NONSTRICT_READ_WRITE, READ_WRITE, TRANSACTIONAL)
 ehcache不支持transaction事务机制,但其他三种可以使用:
      read-only::
        无需修改, 那么就可以对其进行只读 缓存,注意,在此策略下,如果直接修改数据库,即使能够看到前台显示效果,
        但是将对象修改至cache中会报error,cache不会发生作用。另:删除记录会报错,因为不能在read-only模式的对象从cache中删除。
      read-write: 
         需要更新数据,那么使用读/写缓存 比较合适,前提:数据库不可以为serializable transaction isolation level(序列化事务隔离级别)
     nonstrice-read-write:
        只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,那么比较适合使用非严格读/写缓存策略。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,在项目中引入依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency> ``` 然后,在 Spring Boot 启动类中添加 @EnableCaching 注解开启缓存功能: ```java @SpringBootApplication @EnableCaching public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 接下来,需要创建一个配置类,配置 Ehcache 作为缓存管理器: ```java @Configuration @EnableCaching public class EhcacheConfig { @Bean public CacheManager cacheManager() { return new EhCacheCacheManager(ehCacheCacheManager().getObject()); } @Bean public EhCacheManagerFactoryBean ehCacheCacheManager() { EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean(); cmfb.setConfigLocation(new ClassPathResource("ehcache.xml")); cmfb.setShared(true); return cmfb; } } ``` 接着,在项目的 classpath 下新建一个名为 ehcache.xml 的配置文件,并在其中定义一个缓存(cache),作为二级缓存: ```xml <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd" updateCheck="true" monitoring="autodetect"> <cache name="secondLevelCache" maxEntriesLocalHeap="10000" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="3600" diskSpoolBufferSizeMB="20" maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </cache> </ehcache> ``` 最后,在需要使用二级缓存的实体类

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值