Contents
  1. 1. 内容大纲
  2. 2. 源码
  3. 3. Spring的缓存注解
    1. 3.1. 引用博客
    2. 3.2. 常用注解
    3. 3.3. @Cacheable
      1. 3.3.1. value 设置两种方法
      2. 3.3.2. key
      3. 3.3.3. condition
    4. 3.4. @CachePut
    5. 3.5. @CacheEvict
    6. 3.6. @CacheConfig
  4. 4. Mybatis的一级、二级缓存
  5. 5. Ehcache
    1. 5.1. Ehcache特点
    2. 5.2. 引入spring中结合注解
    3. 5.3. Ehcache.xml
    4. 5.4. Hibernate 一级、二级缓存

内容大纲

  • Spring的缓存注解
  • Mybatis的一级、二级缓存
  • Ehcache

源码

  1. Spring 各种注解的源码,这里面service里面有keyGenerator的示例:
    https://github.com/huangzhenshi/SSM_REDIS_ANNOTATION_DEMO

  2. Spring 整合ehcache源码 参考封装在公司PC里面的webTest 项目
    C:\huangzs\缓存\缓存\Spring-ehcache_demos\webTest

Spring的缓存注解

引用博客

常用注解

  • @Cacheable
  • @CachePut
  • @CacheEvict
  • @CacheConfig

@Cacheable

  • value
  • key
  • condition

value 类似于 班级,key类似于学号的概念,例如调用下面的方法,分别用id=1 id=2调用,
会在keys *中产生3个对象,必须要通过 value getById~keys 才找的到\xac\xed\x00\x05t\x00(com.lyz.user.service.UserServicegetById1这个键,再找到对应的真实缓存的值

getById~keys
\xac\xed\x00\x05t\x00(com.lyz.user.service.UserServicegetById2
\xac\xed\x00\x05t\x00(com.lyz.user.service.UserServicegetById1

@Cacheable(value="getById")
public String getById(Integer id) {
return template.selectOne("com.lyz.user.mapper.UserMapper.getNameById", id);
}

value 设置两种方法

一个方法也可以指定多个value

@Cacheable(value="getAllUser")
public List<User> getAllUser() {
return template.selectList("com.lyz.user.mapper.UserMapper.getAllUser");
}
@Cacheable("getAllUser")
public List<User> getAllUser() {
return template.selectList("com.lyz.user.mapper.UserMapper.getAllUser");
}
@Cacheable(value={”cache1”,”cache2”}
public List<User> getAllUser() {
return template.selectList("com.lyz.user.mapper.UserMapper.getAllUser");
}

key

  • 可以通过SpringEL表达式 指定key

    @Cacheable(value="getById", key="'getUserById'+#id")
    public String getUserById(Integer id) {
    return template.selectOne("com.lyz.user.mapper.UserMapper.getNameById", id);
    }
  • 可以通过配置重写keyGenerator的方法,如果重写了的话,同时也指定了key的话,优先取指定的key

condition

支持SpringEl表达式,可以添加 useCache 来动态 支持是否要从缓存中读取数据,还是直接通过数据库中即时的读取数据

@Cacheable(value="getUserById" ,condition="#useCache")
public String getById(Integer id,Boolean useCache) {
return template.selectOne("com.lyz.user.mapper.UserMapper.getNameById", id);
}

@CachePut

  • 每次执行的时候不会查看缓存,直接执行方法
  • 执行完之后,会把最新的结果更新到缓存中
  • 执行完 CachePut的时候,缓存中已经有了结果,如果其他方法的 value 和key值一定用cacheable的话,则可以获取到这个 缓存值

例如下面2个方法, value 和 key一样共享缓存的,如果更新过数据库要更新某个数据的缓存,可以调用第二个方法,同时下次执行第一个缓存方法的时候,会取到更新过后的结果。

@Cacheable(value="getUserById" , key="'getUserById'+#id")
public String getByIdCacheFirst(Integer id) {
System.out.println("search CacheFirst");
return template.selectOne("com.lyz.user.mapper.UserMapper.getNameById", id);
}
@CachePut(value="getUserById" , key="'getUserById'+#id")
public String getByIdDBDirectly(Integer id) {
System.out.println("go to database,then update cache!");
return template.selectOne("com.lyz.user.mapper.UserMapper.getNameById", id);
}

@CacheEvict

清空一个或者多个缓存的 部分或者全部key的缓存

  • 可以定点删除某个缓存下的 某个key的缓存

如下会删除 getUserById的缓存下 getUserById+参数 为key的缓存

@CacheEvict(value="getUserById" , key="'getUserById'+#id")
public String deleteCache(Integer id) {
System.out.println("go go go ");
return null;
}

  • 删除getUserById的缓存中的所有key的缓存

    @CacheEvict(value="getUserById" , allEntries=true)
    public String deleteCache(Integer id) {
    System.out.println("go go go ");
    return null;
    }
  • 删除多个缓存下的所有key的缓存

    @CacheEvict(value={"getUserById","getAllUser"} , allEntries=true)
    public String deleteCache(Integer id) {
    System.out.println("go go go ");
    return null;
    }

@CacheConfig

  • 类级别的缓存标志,所有的方法如果有 @cacheable 并且未指定 value的话都会默认继承
  • 如果没有@Cacheable的方法,不会缓存
  • 如果有@Cacheable的注解,但是指定了 value的话,以指定的value为实际的value

Mybatis的一级、二级缓存

  • mybatis的一级缓存是默认开启的,但是只有在该方法是在事务开启的时候才有效,否则还是一个request当中重复读取的,重点注意
  • mybatis 二级缓存需要配置 开启即可,但是mybatis的二级缓存是针对 mapper的文件的缓存,但是ehcache是方法级别的缓存,所以优先使用 ehcache

Ehcache

Ehcache特点

  • JAVA写的非分布式缓存框架
  • 支持缓存持久化
  • 结合Spring的缓存注解可以实现方法级别的缓存和灵活的配置

引入spring中结合注解

  1. Application.xml

    <!-- 引入ehcache配置 start -->
    <cache:annotation-driven cache-manager="cacheManager" />
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    <property name="cacheManager" ref="ehcache"></property>
    </bean>
    <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    <property name="configLocation" value="classpath:ehcache.xml"></property>
    </bean>
    <!-- 引入ehcache配置 end -->
  2. 引入对应的ehcache.xml文件

然后就可以根据通用Spring 缓存注解一样使用了,注意 value要等于ehcache的 name

Ehcache.xml

  • 配置 cache的name 对应,Spring 注解当中的 value,否则会报错,实现对一类 cacheTest类的缓存 根据key不同缓存
<cache name="cacheTest"
maxElementsInMemory="1000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="1000"
timeToLiveSeconds="2000"/>
@Cacheable(value = "cacheTest", key = "#username")
public List<User> getAll(String username) {
System.out.println("gogogo");
List<User> list = template.selectList("com.test.dao.UserMapper.findAll");
return list;
}
  • 指定缓存文件持久化的路径

    <!-- 指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下 -->
    <diskStore path="C:/huangzs/缓存"/>
  • maxElementsInMemory 最大缓存数
    内存缓存中最多可以存放的元素数量,若放入Cache中的元素超过这个数值,则有以下两
    种情况
    1)若overflowToDisk=true,则会将Cache中多出的元素放入磁盘文件中
    2)若overflowToDisk=false,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素

  • memoryStoreEvictionPolicy

ehcache 中缓存的3 种清空策略:

  1. FIFO ,first in first out ,这个是大家最熟的,先进先出,不多讲了
  2. LFU , Less Frequently Used ,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。
  3. LRU ,Least Recently Used ,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。

LRU 和FIFO的区别是,最先进去的缓存对象如果后来被使用过,则时间戳会改变

  • 标准可用的ehcache.xml 参考
    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd"
    updateCheck="false">
    <!-- 指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下 -->
    <diskStore path="C:/huangzs/缓存"/>
    <defaultCache
    maxElementsInMemory="10000"
    eternal="false"
    overflowToDisk="true"
    timeToIdleSeconds="10"
    timeToLiveSeconds="20"
    diskPersistent="false"
    diskExpiryThreadIntervalSeconds="120"/>
    <cache name="cacheTest"
    maxElementsInMemory="1000"
    eternal="false"
    overflowToDisk="true"
    timeToIdleSeconds="1000"
    timeToLiveSeconds="2000"/>
    <cache name="cacheTest3"
    maxElementsInMemory="10000"
    eternal="false"
    overflowToDisk="true"
    timeToIdleSeconds="1000"
    timeToLiveSeconds="2000"
    diskPersistent="false"
    diskExpiryThreadIntervalSeconds="120"/>
    </ehcache>

Hibernate 一级、二级缓存

  • hibernate的二级缓存是基于HQL或者 SQL的二级缓存
    例如根据ID查询某个对象的时候,开启配置了二级缓存,就会从缓存中读取结果集。

参考这个对Bean进行缓存设置

@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
@Entity
@Table(name = "region")
public class Region implements Serializable {

  • Ehcache 实战
    E学E用利用的是hibernate的二级缓存
  • 对地区类进行二级缓存
    @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
    @Entity
    @Table(name = "region")
    public class Region implements Serializable {

ehcache.xml 里面的配置到这个Bean

<cache name="com.ge.dh.edu.domain.Region"
maxElementsInMemory="5000"
eternal="true"
overflowToDisk="true"
/>

Contents
  1. 1. 内容大纲
  2. 2. 源码
  3. 3. Spring的缓存注解
    1. 3.1. 引用博客
    2. 3.2. 常用注解
    3. 3.3. @Cacheable
      1. 3.3.1. value 设置两种方法
      2. 3.3.2. key
      3. 3.3.3. condition
    4. 3.4. @CachePut
    5. 3.5. @CacheEvict
    6. 3.6. @CacheConfig
  4. 4. Mybatis的一级、二级缓存
  5. 5. Ehcache
    1. 5.1. Ehcache特点
    2. 5.2. 引入spring中结合注解
    3. 5.3. Ehcache.xml
    4. 5.4. Hibernate 一级、二级缓存