Hibernate之二级缓存

一:二级缓存简介

为什么需要缓存:

      查询大量数据时更快,拉高程序的性能

什么样的数据需要缓存:

      很少被修改或根本不改的数据 数据字典

业务场景比如:耗时较高的统计分析sql、电话账单查询sql等

关系型数据库:

数据与数据之间存在关系(联系)的数据库 mysql/Oracle、sqlserver

非关系型数据库(数据与数据之间是不存在关系的,key-value):

  • 基于文件存储的数据库:ehcache
  • 基于内存存储的数据库:redis、memcache
  • 基于文档存储的数据库:mongodb

ehcache是什么:

Ehcache 是现在最流行的纯Java开源缓存框架,配置简单、结构清晰、功能强大

我们来用map简单测试一下缓存原理:

1package com.ht.six.test; 2 3import java.util.HashMap; 4import java.util.Map; 5 6/** 7 * 利用map集合简易实现缓存原理 8 * @author Administrator 9 * 10 */ 11public class EhcacheDemo1 { 12 static Map<String, Object> cache = new HashMap<String, Object>(); 13 static Object getValue(String key) { 14 Object value = cache.get(key); 15 System.out.println("从缓存中获取数据。。。。"); 16 if(value == null) { 17 System.out.println("从软件相对应的配置文件中获取数据。。。"); 18 cache.put(key, new String[] {"zs"}); 19 return cache.get(key); 20 } 21 return value; 22 } 23 24 /** 25 * 1.从缓存中获取数据。。。。 26 * 2.从软件相对应的配置文件中获取数据。。。 27 * 3."zs" 28 * 4.从缓存中获取数据。。。。 29 * 5."zs" 30 * @param args 31 */ 32 public static void main(String[] args) { 33 System.out.println(getValue("sname")); 34 System.out.println(getValue("sname")); 35 } 36}

运行原理图解:

我们来看一下运行结果:

 ehcache简介

ehcache特点:

  • 够快

     Ehcache的发行有一段时长了,经过几年的努力和不计其数的性能测试,Ehcache终被设计于large, high concurrency systems.

  • 够简单

    开发者提供的接口非常简单明了,从Ehcache的搭建到运用运行仅仅需要的是你宝贵的几分钟。其实很多开发者都不知道自己用在用Ehcache,Ehcache被广泛的运用于其他的开源项目

  • 够小

关于这点的特性,官方给了一个很可爱的名字small foot print ,一般Ehcache的发布版本不会到2M,V 2.2.3 才 668KB。

  • 够轻量

核心程序仅仅依赖slf4j这一个包,没有之一!

  • 好扩展

Ehcache提供了对大数据的内存和硬盘的存储,最近版本允许多实例、保存对象高灵活性、提供LRU、LFU、FIFO淘汰算法,基础属性支持热配置、支持的插件多

  • 监听器

缓存管理器监听器 (CacheManagerListener)和 缓存监听器(CacheEvenListener),做一些统计或数据一致性广播挺好用的

  • 分布式缓存

从Ehcache 1.2开始,支持高性能的分布式缓存,兼具灵活性和扩展性

核心接口:

  1. CacheManager:缓存管理器
  2. Cache:缓存对象,缓存管理器内可以放置若干cache,存放数据的实质,所有cache都实现了Ehcache接口
  3. Element:单条缓存数据的组成单位

ehcache的使用

首先我们在POM.XML中导入相关依赖

1<properties> 2 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 3 <maven.compiler.source>1.8</maven.compiler.source> 4 <maven.compiler.target>1.8</maven.compiler.target> 5 <junit.version>4.12</junit.version> 6 <servlet.version>4.0.0</servlet.version> 7 <hibernate.version>5.2.12.Final</hibernate.version> 8 <mysql.driver.version>5.1.46</mysql.driver.version> 9 <ehcache.version>2.10.0</ehcache.version> 10 <slf4j-api.version>1.7.7</slf4j-api.version> 11 <log4j-api.version>2.9.1</log4j-api.version> 12 </properties> 13 <dependencies> 14 <dependency> 15 <groupId>junit</groupId> 16 <artifactId>junit</artifactId> 17 <version>${junit.version}</version> 18 <scope>test</scope> 19 </dependency> 20<dependency> 21 <groupId>javax.servlet</groupId> 22 <artifactId>javax.servlet-api</artifactId> 23 <version>${servlet.version}</version> 24 <scope>provided</scope> 25 </dependency> 26 <dependency> 27 <groupId>org.hibernate</groupId> 28 <artifactId>hibernate-core</artifactId> 29 <version>${hibernate.version}</version> 30 </dependency> 31 <dependency> 32 <groupId>mysql</groupId> 33 <artifactId>mysql-connector-java</artifactId> 34 <version>${mysql.driver.version}</version> 35 </dependency> 36 <dependency> 37 <groupId>net.sf.ehcache</groupId> 38 <artifactId>ehcache</artifactId> 39 <version>${ehcache.version}</version> 40 </dependency> 41 42 <dependency> 43 <groupId>org.hibernate</groupId> 44 <artifactId>hibernate-ehcache</artifactId> 45 <version>${hibernate.version}</version> 46 </dependency> 47 <!-- slf4j核心包 --> 48 <dependency> 49 <groupId>org.slf4j</groupId> 50 <artifactId>slf4j-api</artifactId> 51 <version>${slf4j-api.version}</version> 52 </dependency> 53 <dependency> 54 <groupId>org.slf4j</groupId> 55 <artifactId>jcl-over-slf4j</artifactId> 56 <version>${slf4j-api.version}</version> 57 <scope>runtime</scope> 58 </dependency> 59 60 <!--用于与slf4j保持桥接 --> 61 <dependency> 62 <groupId>org.apache.logging.log4j</groupId> 63 <artifactId>log4j-slf4j-impl</artifactId> 64 <version>${log4j-api.version}</version> 65 </dependency> 66 <!--核心log4j2jar包 --> 67 <dependency> 68 <groupId>org.apache.logging.log4j</groupId> 69 <artifactId>log4j-api</artifactId> 70 <version>${log4j-api.version}</version> 71 </dependency> 72 <dependency> 73 <groupId>org.apache.logging.log4j</groupId> 74 <artifactId>log4j-core</artifactId> 75 <version>${log4j-api.version}</version> 76 </dependency> 77 </dependencies>

用二级缓存来演示存储数据

    导入相关配置文件

  ehcache.xml

1<?xml version="1.0" encoding="UTF-8"?> 2<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" 4 updateCheck="false"> 5 <!--磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存--> 6 <!--path:指定在硬盘上存储对象的路径--> 7 <!--java.io.tmpdir 是默认的临时文件路径。 可以通过如下方式打印出具体的文件路径 System.out.println(System.getProperty("java.io.tmpdir"));--> 8 <diskStore path="D://xxx"/> 9 10 11 <!--defaultCache:默认的管理策略--> 12 <!--eternal:设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断--> 13 <!--maxElementsInMemory:在内存中缓存的element的最大数目--> 14 <!--overflowToDisk:如果内存中数据超过内存限制,是否要缓存到磁盘上--> 15 <!--diskPersistent:是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false--> 16 <!--timeToIdleSeconds:对象空闲时间(单位:秒),指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问--> 17 <!--timeToLiveSeconds:对象存活时间(单位:秒),指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问--> 18 <!--memoryStoreEvictionPolicy:缓存的3 种清空策略--> 19 <!--FIFO:first in first out (先进先出)--> 20 <!--LFU:Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存--> 21 <!--LRU:Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存--> 22 <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false" 23 timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/> 24</ehcache>

  EhcacheUtil类

1package com.ht.six.util; 2 3import net.sf.ehcache.Cache; 4import net.sf.ehcache.CacheManager; 5import net.sf.ehcache.Element; 6 7import java.io.InputStream; 8 9public class EhcacheUtil { 10 11 private static CacheManager cacheManager; 12 13 static { 14 try { 15 InputStream is = EhcacheUtil.class.getResourceAsStream("/ehcache.xml"); 16 cacheManager = CacheManager.create(is); 17 } catch (Exception e) { 18 throw new RuntimeException(e); 19 } 20 } 21 22 private EhcacheUtil() { 23 } 24 25 public static void put(String cacheName, Object key, Object value) { 26 Cache cache = cacheManager.getCache(cacheName); 27 if (null == cache) { 28 //以默认配置添加一个名叫cacheName的Cache 29 cacheManager.addCache(cacheName); 30 cache = cacheManager.getCache(cacheName); 31 } 32 cache.put(new Element(key, value)); 33 } 34 35 36 public static Object get(String cacheName, Object key) { 37 Cache cache = cacheManager.getCache(cacheName); 38 Element element = cache.get(key); 39 return null == element ? null : element.getValue(); 40 } 41 42 public static void remove(String cacheName, Object key) { 43 Cache cache = cacheManager.getCache(cacheName); 44 cache.remove(key); 45 } 46}

测试类:

1package com.ht.six.test; 2 3import com.ht.six.util.EhcacheUtil; 4 5/** 6 * 演示利用缓存存储数据 7 * @author Administrator 8 * 9 */ 10public class EhcacheDemo2 { 11 public static void main(String[] args) { 12 System.out.println(System.getProperty("java.io.tmpdir")); 13 EhcacheUtil.put("com.ht.four.entity.Book", 11, "zhangsan"); 14 System.out.println(EhcacheUtil.get("com.ht.four.entity.Book", 11)); 15 } 16}

若是自己没有去配置槽中的内容,管理器一般就是自动规划为默认配置,不会存储到硬盘里面去

什么是槽?由下面的图告诉你cache的内部结构

把槽中数据修改一下测试一下

1<!--name: Cache的名称,必须是唯一的(ehcache会把这个cache放到HashMap里)--> 2 <cache name="com.ht.one.entity.User" eternal="false" maxElementsInMemory="100" 3 overflowToDisk="true" diskPersistent="true" timeToIdleSeconds="0" 4 timeToLiveSeconds="300" memoryStoreEvictionPolicy="LRU"/>

测试结果中,我们在D盘中发现存储进去的文件:

hibernate中使用二级缓存(ehcache)

  • 依赖包已经在上面全部导入 所以这里就不重复了

  hibernate一级缓存使用

1/** 2 * 默认情况下,sql语句形成了三次,这里为了提高性能,必须使用二级缓存SessionFactory缓存 3 * <!-- 开启二级缓存 --> 4 * <property name="hibernate.cache.use_second_level_cache">true</property> 5 <!-- 开启查询缓存 --> 6 <property name="hibernate.cache.use_query_cache">true</property> 7 <!-- EhCache驱动 --> 8 <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> 9 10 映射文件中添加标签 11 <cache usage="read-write" region="com.javaxl.one.entity.User"/> 12 这里的region指的是Ehcache.xml中cacheName 13 * @param args 14 */ 15 public static void main(String[] args) { 16 UserDao userDao = new UserDao(); 17 User u = new User(); 18 u.setId(7); 19 User user = userDao.get(u); 20 System.out.println(user); 21 User user2 = userDao.get(u); 22 System.out.println(user2); 23 User user3 = userDao.get(u); 24 System.out.println(user3); 25 26 }

因为一个session中只生产一个sql语句,所以这里用了多个session,要是小数据还可行,大量数据就大大降低性能,那么就要用到二级缓存了。

  • hibernate.cfg.xml中添加二级缓存相关配置

         <!-- 开启二级缓存 --> <property name="hibernate.cache.use_second_level_cache">true</property> <!-- 开启查询缓存 --> <property name="hibernate.cache.use_query_cache">true</property> <!-- EhCache驱动 --> <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.internal.EhCacheRegionFactory</property>

  • 对应的映射文件中添加缓存配置 User.hbm.xml

    <!-- 添加缓存标号 指定槽 --> <cache usage="read-write" region="com.ht.one.entity.User"/>
  • 调用 测试方法

    /** * 同一个session,sql语句只生成一次,这里用到了一级缓存 * * session级别的缓存就是一级缓存 * sessionfactory级别的缓存就是二级缓存 * 默认的一级缓存开启的 */ public static void test1() { Session session = SessionFactoryUtils.openSession(); Transaction transaction = session.beginTransaction();

    1 User user = session.get(User.class, 7); 2 System.out.println(user); 3 User user2 = session.get(User.class, 7); 4 System.out.println(user2); 5 User user3 = session.get(User.class, 7); 6 System.out.println(user3); 7 8 transaction.commit(); 9 session.close(); 10}

EhcacheDemo4

1package com.ht.six.test; 2 3import java.util.List; 4 5import org.hibernate.Session; 6import org.hibernate.Transaction; 7import org.hibernate.query.Query; 8 9import com.ht.two.util.SessionFactoryUtils; 10 11 12/** 13 * hibernate二级缓存不会同时缓存多条数据 14 * @author Administrator 15 * 16 */ 17public class EhcacheDemo4 { 18 public static void main(String[] args) { 19 Session session = SessionFactoryUtils.openSession(); 20 Transaction transaction = session.beginTransaction(); 21 22 Query query = session.createQuery("from User"); 23 query.setCacheable(true); 24 List list = query.list(); 25 System.out.println(list); 26 List list2 = query.list(); 27 System.out.println(list2); 28 List list3 = query.list(); 29 System.out.println(list3); 30 31 32 transaction.commit(); 33 session.close(); 34 } 35}

发现他也执行多次

  原因:对于查询单条数据的时候,缓存机制是默认用一级缓存的,若是想要用二级缓存来提高性能,还得靠自己手动开启二级缓存

query.setCacheable(true);
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )