Hibernate之二级缓存

Posted xcn123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate之二级缓存相关的知识,希望对你有一定的参考价值。

Hibernate之二级缓存

1. 为什么需要缓存
拉高程序的性能

数据库:

          关系型数据库:数据与数据之间存在关系(联系)的数据库 mysql/Oracle、sqlserver
          非关系型数据库:数据与数据之间是不存在关系的,key-value
          1、基于文件存储的数据库:ehcache
          2、基于内存存储的数据库:redis、memcache
          3、基于文档存储的数据库:mongodb

2. 什么样的数据需要缓存
很少被修改或根本不改的数据 数据字典
业务场景比如:耗时较高的统计分析sql、电话账单查询sql等

缓存使用场景:

技术图片

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

4. ehcache的特点
4.1 够快
Ehcache的发行有一段时长了,经过几年的努力和不计其数的性能测试,Ehcache终被设计于large, high concurrency systems.
4.2 够简单
开发者提供的接口非常简单明了,从Ehcache的搭建到运用运行仅仅需要的是你宝贵的几分钟。其实很多开发者都不知道自己用在用Ehcache,Ehcache被广泛的运用于其他的开源项目
4.3 够袖珍
关于这点的特性,官方给了一个很可爱的名字small foot print ,一般Ehcache的发布版本不会到2M,V 2.2.3 才 668KB。
4.4 够轻量
核心程序仅仅依赖slf4j这一个包,没有之一!
4.5 好扩展
Ehcache提供了对大数据的内存和硬盘的存储,最近版本允许多实例、保存对象高灵活性、提供LRU、LFU、FIFO淘汰算法,基础属性支持热配置、支持的插件多
4.6 监听器
缓存管理器监听器 (CacheManagerListener)和 缓存监听器(CacheEvenListener),做一些统计或数据一致性广播挺好用的
4.7 分布式缓存
从Ehcache 1.2开始,支持高性能的分布式缓存,兼具灵活性和扩展性

ehcache内存结构:

技术图片

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

 导入工具类

EhcacheUtil
 1 package com.javaxl.six.util;
 2 
 3 import net.sf.ehcache.Cache;
 4 import net.sf.ehcache.CacheManager;
 5 import net.sf.ehcache.Element;
 6 
 7 import java.io.InputStream;
 8 
 9 public 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 

 导入日志文件log4j2.xml

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 
  3 <!-- status : 指定log4j本身的打印日志的级别.ALL< Trace < DEBUG < INFO < WARN < ERROR 
  4     < FATAL < OFF。 monitorInterval : 用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s. -->
  5 <Configuration status="WARN" monitorInterval="30">
  6     <Properties>
  7         <!-- 配置日志文件输出目录 $sys:user.home -->
  8         <Property name="LOG_HOME">/root/workspace/lucenedemo/logs</Property>
  9         <property name="ERROR_LOG_FILE_NAME">/root/workspace/lucenedemo/logs/error</property>
 10         <property name="WARN_LOG_FILE_NAME">/root/workspace/lucenedemo/logs/warn</property>
 11         <property name="PATTERN">%dyyyy-MM-dd HH:mm:ss.SSS [%t-%L] %-5level %logger36 - %msg%n</property>
 12     </Properties>
 13 
 14     <Appenders>
 15         <!--这个输出控制台的配置 -->
 16         <Console name="Console" target="SYSTEM_OUT">
 17             <!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
 18             <ThresholdFilter level="trace" onMatch="ACCEPT"
 19                 onMismatch="DENY" />
 20             <!-- 输出日志的格式 -->
 21             <!-- %dyyyy-MM-dd HH:mm:ss, SSS : 日志生产时间 %p : 日志输出格式 %c : logger的名称 
 22                 %m : 日志内容,即 logger.info("message") %n : 换行符 %C : Java类名 %L : 日志输出所在行数 %M 
 23                 : 日志输出所在方法名 hostName : 本地机器名 hostAddress : 本地ip地址 -->
 24             <PatternLayout pattern="$PATTERN" />
 25         </Console>
 26 
 27         <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,这个也挺有用的,适合临时测试用 -->
 28         <!--append为TRUE表示消息增加到指定文件中,false表示消息覆盖指定的文件内容,默认值是true -->
 29         <File name="log" fileName="logs/test.log" append="false">
 30             <PatternLayout
 31                 pattern="%dyyyy-MM-dd HH:mm:ss.SSS [%t] %-5level %logger36 - %msg%n" />
 32         </File>
 33         <!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size, 则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档 -->
 34         <RollingFile name="RollingFileInfo" fileName="$LOG_HOME/info.log"
 35             filePattern="$LOG_HOME/$$date:yyyy-MM/info-%dyyyy-MM-dd-%i.log">
 36             <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) -->
 37             <ThresholdFilter level="info" onMatch="ACCEPT"
 38                 onMismatch="DENY" />
 39             <PatternLayout
 40                 pattern="%dyyyy-MM-dd HH:mm:ss.SSS [%t] %-5level %logger36 - %msg%n" />
 41             <Policies>
 42                 <!-- 基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。 modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am...而不是7am. -->
 43                 <!-- 关键点在于 filePattern后的日期格式,以及TimeBasedTriggeringPolicy的interval, 日期格式精确到哪一位,interval也精确到哪一个单位 -->
 44                 <!-- log4j2的按天分日志文件 : info-%dyyyy-MM-dd-%i.log -->
 45                 <TimeBasedTriggeringPolicy interval="1"
 46                     modulate="true" />
 47                 <!-- SizeBasedTriggeringPolicy:Policies子节点, 基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小. -->
 48                 <!-- <SizeBasedTriggeringPolicy size="2 kB" /> -->
 49             </Policies>
 50         </RollingFile>
 51 
 52         <RollingFile name="RollingFileWarn" fileName="$WARN_LOG_FILE_NAME/warn.log"
 53             filePattern="$WARN_LOG_FILE_NAME/$$date:yyyy-MM/warn-%dyyyy-MM-dd-%i.log">
 54             <ThresholdFilter level="warn" onMatch="ACCEPT"
 55                 onMismatch="DENY" />
 56             <PatternLayout
 57                 pattern="%dyyyy-MM-dd HH:mm:ss.SSS [%t] %-5level %logger36 - %msg%n" />
 58             <Policies>
 59                 <TimeBasedTriggeringPolicy />
 60                 <SizeBasedTriggeringPolicy size="2 kB" />
 61             </Policies>
 62             <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->
 63             <DefaultRolloverStrategy max="20" />
 64         </RollingFile>
 65 
 66         <RollingFile name="RollingFileError" fileName="$ERROR_LOG_FILE_NAME/error.log"
 67             filePattern="$ERROR_LOG_FILE_NAME/$$date:yyyy-MM/error-%dyyyy-MM-dd-HH-mm-%i.log">
 68             <ThresholdFilter level="error" onMatch="ACCEPT"
 69                 onMismatch="DENY" />
 70             <PatternLayout
 71                 pattern="%dyyyy-MM-dd HH:mm:ss.SSS [%t] %-5level %logger36 - %msg%n" />
 72             <Policies>
 73                 <!-- log4j2的按分钟 分日志文件 : warn-%dyyyy-MM-dd-HH-mm-%i.log -->
 74                 <TimeBasedTriggeringPolicy interval="1"
 75                     modulate="true" />
 76                 <!-- <SizeBasedTriggeringPolicy size="10 MB" /> -->
 77             </Policies>
 78         </RollingFile>
 79 
 80     </Appenders>
 81 
 82     <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效 -->
 83     <Loggers>
 84         <!--过滤掉spring和mybatis的一些无用的DEBUG信息 -->
 85         <logger name="org.springframework" level="INFO"></logger>
 86         <logger name="org.mybatis" level="INFO"></logger>
 87 
 88         <!-- 第三方日志系统 -->
 89         <logger name="org.springframework" level="ERROR" />
 90         <logger name="org.hibernate" level="ERROR" />
 91         <logger name="org.apache.struts2" level="ERROR" />
 92         <logger name="com.opensymphony.xwork2" level="ERROR" />
 93         <logger name="org.jboss" level="ERROR" />
 94 
 95 
 96         <!-- 配置日志的根节点 -->
 97         <root level="all">
 98             <appender-ref ref="Console" />
 99             <appender-ref ref="RollingFileInfo" />
100             <appender-ref ref="RollingFileWarn" />
101             <appender-ref ref="RollingFileError" />
102         </root>
103 
104     </Loggers>
105 
106 </Configuration>

 利用map集合简易实现缓存原理

 1 package com.MavenHibernate.six.test;
 2  
 3 import java.util.HashMap;
 4 import java.util.Map;
 5  
 6 /**
 7  * 利用map集合简易实现缓存原理
 8  * @author Administrator
 9  *
10  */
11 public 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("aaa1");
16         //如果第一次为空,就会在map集合中加入,第二次的时候就有了
17         if(value == null) 
18             System.out.println("XFQ");
19             cache.put(key, new String[] "zs");
20             return cache.get(key);
21         
22         return value;
23     
24      
25     public static void main(String[] args) 
26         System.out.println(getValue("sname"));
27         System.out.println(getValue("sname"));
28     
29 

利用缓存存储数据

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 
25 
26     <!--name: Cache的名称,必须是唯一的(ehcache会把这个cache放到HashMap里)-->
27     <cache name="com.xieminglu.one.entity.User" eternal="false" maxElementsInMemory="100"
28            overflowToDisk="true" diskPersistent="false" timeToIdleSeconds="0"
29            timeToLiveSeconds="300" memoryStoreEvictionPolicy="LRU"/>
30 </ehcache>

EhcacheDemo2 测试利用缓存存储数据

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

 6.hibernate缓存

一级缓存
session

 1 /**
 2      * 同一个session,sql语句只生成一次,这里用到了一级缓存
 3      */
 4     public static void main(String[] args) 
 5         Session session = SessionFactoryUtils.openSession();
 6         Transaction transaction = session.beginTransaction();
 7         
 8         User user = session.get(User.class, 7);
 9         System.out.println(user);
10         User user2 = session.get(User.class, 7);
11         System.out.println(user2);
12         User user3 = session.get(User.class, 7);
13         System.out.println(user3);
14         
15         transaction.commit();
16         session.close();
17     

二级缓存
 hibernate.cfg.xml中添加二级缓存

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

在user.hbm.xml中开启二级缓存(指定实体类开启二级缓存)

 1 <cache usage="read-write" region="com.MavenHibernate.entity.User"/>` 

UserDao 
 1 package com.MavenHibernate.six.dao;
 2  
 3 import org.hibernate.Session;
 4 import org.hibernate.Transaction;
 5  
 6 import com.MavenHbernate.entity.User;
 7 import com.MavenHibernate.two.util.SessionFactoryUtils;
 8  
 9 public class UserDao 
10     public User get(User u) 
11         Session session = SessionFactoryUtils.openSession();
12         Transaction transaction = session.beginTransaction();
13          
14         User user = session.get(User.class, u.getId());
15          
16          
17         transaction.commit();
18         session.close();
19         return user;
20     
21  
22      
23 
查单个用户使用了缓存
EhcacheDemo3 
 1 package com.MavenHidernate.six.test;
 2  
 3 import org.hibernate.Session;
 4 import org.hibernate.Transaction;
 5  
 6  
 7 import com.MavenHidernatel.entity.User;
 8 import com.MavenHidernatel.six.dao.UserDao;
 9 import com.MavenHidernatel.two.util.SessionFactoryUtils;
10  
11  
12 /**
13  * 演示查单个用户使用了缓存
14  * @author Administrator
15  *
16  */
17 public class EhcacheDemo3 
18     /**
19      * 默认情况下,sql语句形成了三次,这里为了提高性能,必须使用二级缓存SessionFactory缓存
20      *  <!-- 开启二级缓存 -->
21      *  <property name="hibernate.cache.use_second_level_cache">true</property>
22       <!-- 开启查询缓存 -->
23       <property name="hibernate.cache.use_query_cache">true</property>
24       <!-- EhCache驱动 -->
25       <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
26        
27         映射文件中添加标签
28         <cache usage="read-write" region="com.zl.one.entity.User"/>
29         这里的region指的是Ehcache.xml中cacheName
30      * @param args
31      */
32     public static void main() 
33         UserDao userDao  = new UserDao();
34         User u = new User();
35         u.setId(7);
36         User user = userDao.get(u);
37         System.out.println(user);
38         User user2 = userDao.get(u);
39         System.out.println(user2);
40         User user3 = userDao.get(u);
41         System.out.println(user3);
42          
43     
44      
45     /**
46      * 同一个session,sql语句只生成一次,这里用到了一级缓存
47      */
48     public static void main(String[] args) 
49         Session session = SessionFactoryUtils.openSession();
50         Transaction transaction = session.beginTransaction();
51          
52         User user = session.get(User.class, 7);
53         System.out.println(user);
54         User user2 = session.get(User.class, 7);
55         System.out.println(user2);
56         User user3 = session.get(User.class, 7);
57         System.out.println(user3);
58          
59         transaction.commit();
60         session.close();
61     
62 

 hibernate二级缓存不会同时缓存多条数据

 1 package com.MavenHibernate.six.test;
 2  
 3 import java.util.List;
 4  
 5 import org.hibernate.Session;
 6 import org.hibernate.Transaction;
 7 import org.hibernate.query.Query;
 8  
 9 import com.MavenHibernate.two.util.SessionFactoryUtils;
10  
11  
12 /**
13  * hibernate二级缓存不会同时缓存多条数据
14  * @author Administrator
15  *
16  */
17 public 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 

 

以上是关于Hibernate之二级缓存的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate之二级缓存

Hibernate之二级缓存

hibernate之二级缓存

Java面试题:Hibernate的二级缓存与Hibernate多表查询

hibernate之二级缓存

SSH整合缓存之-Memcached作为hibernate的二级缓存