当前位置:   article > 正文

Spring Cache和EhCache实现缓存管理_spring cache ehcache

spring cache ehcache

1、认识 Spring Cache

Spring Cache是Spring提供的一整套缓存解决方案。它本身并不提供缓存实现,而是提供统一的接口和代码规范、配置、注解等,以便整合各种Cache方案,使用户不用关心Cache的细节。

Spring支持“透明”地向应用程序添加缓存,将缓存应用于方法,在方法执行前检查缓存中是否有可用的数据。这样可以减少方法执行的次数,同时提高响应的速度。缓存的应用方式“透明”,不会对调用者造成任何干扰。只要通过注解@EnableCaching启用了缓存支持,Spring Boot就会自动处理好缓存的基础配置。

Spring Cache作用在方法上。当调用一个缓存方法时,会把该方法参数和返回结果作为一个“键值对”(key / value)存放在缓存中,下次用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。所以在使用Spring Cache时,要保证在缓存的方法和方法参数相同时返回相同的结果。

Spring Boot提供的声明式缓存(cache)注解,如下表:

注解说明
@EnableCaching开启缓存。
@Cacheable可以作用在类和方法上,以键值对的方式缓存类或方法的返回值。
@CachePut方法被调用,然后结果被缓存。
@CacheEvict清空缓存。
@Caching用来组合多个注解标签。

声明式缓存注解的详细使用:《Spring使用Cache、整合Ehcache》

 

2、认识 EhCache

Spring Boot支持多种不同的缓存产品。在默认情况下使用的是简单缓存,不建议在正式环境中使用。我们可以配置一些更加强大的缓存,比如Ehcache。

Ehcache是一种广泛使用的开源Java分布式缓存,它具有内存和磁盘存储、缓存加载器、缓存扩展、缓存异常处理、GZIP缓存、Servlet 过滤器,以及支持 REST 和 SOAP API 等特点。

 

3、创建SpringBoot与MyBatis的整合项目

【实例】创建SpringBoot与MyBatis的整合项目,实现用户信息的查询、新增、修改、删除功能。并使用 Spring Cache 和 EhCache 实现缓存管理,执行结果如下图:

3.1 创建数据表

在MySQL数据库中创建用户信息表(tb_user),并添加数据。

  1. -- 判断数据表是否存在,存在则删除
  2. DROP TABLE IF EXISTS tb_user;
  3. -- 创建“用户信息”数据表
  4. CREATE TABLE IF NOT EXISTS tb_user
  5. (
  6. user_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '用户编号',
  7. user_name VARCHAR(50) NOT NULL COMMENT '用户姓名',
  8. age INT DEFAULT(0) NOT NULL COMMENT '年龄',
  9. blog_url VARCHAR(50) NOT NULL COMMENT '博客地址',
  10. blog_remark VARCHAR(50) COMMENT '博客信息'
  11. ) COMMENT = '用户信息表';
  12. -- 添加数据
  13. INSERT INTO tb_user(user_name,age,blog_url,blog_remark) VALUES('pan_junbiao的博客',32,'https://blog.csdn.net/pan_junbiao','您好,欢迎访问 pan_junbiao的博客');

3.2 创建项目 

(1)创建SpringBoot项目,项目结构如下图:

(2)添加pom.xml配置信息

在pom.xml配置文件中添加MyBatis、 MySQL的JDBC数据库驱动、Spring Boot 缓存支持启动器、Ehcache 缓存等。

  1. <!-- MyBatis与SpringBoot整合依赖 -->
  2. <dependency>
  3. <groupId>org.mybatis.spring.boot</groupId>
  4. <artifactId>mybatis-spring-boot-starter</artifactId>
  5. <version>2.1.3</version>
  6. </dependency>
  7. <!-- MySQL的JDBC数据库驱动 -->
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <version>8.0.20</version>
  12. </dependency>
  13. <!-- 引入Thymeleaf模板引擎 -->
  14. <dependency>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  17. </dependency>
  18. <!-- Spring Boot缓存支持启动器 -->
  19. <dependency>
  20. <groupId>org.springframework.boot</groupId>
  21. <artifactId>spring-boot-starter-cache</artifactId>
  22. <version>2.3.2.RELEASE</version>
  23. </dependency>
  24. <!-- Ehcache缓存管理器 -->
  25. <dependency>
  26. <groupId>net.sf.ehcache</groupId>
  27. <artifactId>ehcache</artifactId>
  28. </dependency>

(3)配置相关信息

将默认的application.properties文件的后缀修改为“.yml”,即配置文件名称为:application.yml,并配置以下信息:

  1. #Spring配置
  2. spring:
  3. #缓存管理器
  4. cache:
  5. type: ehcache
  6. ehcache:
  7. config: classpath:ehcache.xml #缓存加载配置文件
  8. #使用Thymeleaf模板引擎
  9. thymeleaf:
  10. mode: HTML5
  11. encoding: UTF-8
  12. cache: false #使用Thymeleaf模板引擎,关闭缓存
  13. servlet:
  14. content-type: text/html
  15. #DataSource数据源
  16. datasource:
  17. url: jdbc:mysql://localhost:3306/db_admin?useSSL=false&amp
  18. username: root
  19. password: 123456
  20. driver-class-name: com.mysql.cj.jdbc.Driver
  21. #MyBatis配置
  22. mybatis:
  23. type-aliases-package: com.pjb.entity #别名定义
  24. configuration:
  25. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #指定 MyBatis 所用日志的具体实现,未指定时将自动查找
  26. map-underscore-to-camel-case: true #开启自动驼峰命名规则(camel case)映射
  27. lazy-loading-enabled: true #开启延时加载开关
  28. aggressive-lazy-loading: false #将积极加载改为消极加载(即按需加载),默认值就是false
  29. #lazy-load-trigger-methods: "" #阻挡不相干的操作触发,实现懒加载
  30. cache-enabled: true #打开全局缓存开关(二级环境),默认值就是true

 

4、配置EhCache缓存管理器

4.1 创建 ehcache.xml 配置文件

在 resources (资源目录)下,创建 ehcache.xml 配置文件,配置信息如下:

  1. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
  2. <!-- 这个是磁盘存储路径,当内存缓存满了的时候,就会往这里面放,
  3. java.io.tmdir是操作系统缓存的临时目录,不同操作系统缓存目录不一样 -->
  4. <diskStore path="java.io.tmpdir"/>
  5. <!--defaultCache:echcache的默认缓存策略 -->
  6. <defaultCache
  7. maxElementsInMemory="10000"
  8. eternal="false"
  9. timeToIdleSeconds="120"
  10. timeToLiveSeconds="120"
  11. maxElementsOnDisk="10000000"
  12. diskExpiryThreadIntervalSeconds="120"
  13. memoryStoreEvictionPolicy="LRU">
  14. <persistence strategy="localTempSwap"/>
  15. </defaultCache>
  16. <cache name="userCache"
  17. maxElementsInMemory="10000"
  18. eternal="false"
  19. timeToIdleSeconds="120"
  20. timeToLiveSeconds="120"
  21. maxElementsOnDisk="10000000"
  22. diskExpiryThreadIntervalSeconds="120"
  23. memoryStoreEvictionPolicy="LRU">
  24. <persistence strategy="localTempSwap"/>
  25. </cache>
  26. </ehcache>

配置属性说明: 

属性说明
<diskStore path="java.io.tmpdir"/>这个是磁盘存储路径,当内存缓存满了的时候,就会往这里面放,java.io.tmdir是操作系统缓存的临时目录,不同操作系统缓存目录不一样。
maxElementsInMemory内存缓存中最多可以存放的元素数量,若放入Cache中的元素超过这个数值,则有以下两种情况:
(1)若 overflowToDisk=true,则会将Cache中多出的元素放入磁盘文件中。
(2)若 overflowToDisk=false,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素。
overflowToDisk内存不足时,是否启用磁盘缓存。
eternal缓存中对象是否永久有效。
timeToIdleSeconds缓存数据在失效前的允许闲置时间(单位:秒),仅当 eternal=false 时使用,默认值是0表示可闲置时间无穷大,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除。
timeToLiveSeconds缓存数据的总的存活时间(单位:秒),仅当 eternal=false 时使用,从创建开始计时,失效结束。
maxElementsOnDisk磁盘缓存中最多可以存放的元素数量,0表示无穷大。
diskExpiryThreadIntervalSeconds磁盘缓存的清理线程运行间隔,默认是120秒。
memoryStoreEvictionPolicy内存存储与释放策略,即达到 maxElementsInMemory 限制时,Ehcache会根据指定策略清理内存,共有三种策略,分别为LRU(最近最少使用)、LFU(最常用的)、FIFO(先进先出)。
defaultCache默认缓存方式。
cache自定义的缓存方式,自行设置 name。

4.2 配置缓存管理器

在 application.yml 配置文件中配置目标缓存管理器,支持 Ehcache、Generic、Redis、Jcache等。这里配置使用Ehcache。

  1. #Spring配置
  2. spring:
  3. #缓存管理器
  4. cache:
  5. type: ehcache
  6. ehcache:
  7. config: classpath:ehcache.xml #缓存加载配置文件

4.3 开启缓存功能

在SpringBoot项目启动入口类中添加注解@EnableCaching,开启缓存功能。

  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. import org.springframework.cache.annotation.EnableCaching;
  4. @SpringBootApplication
  5. @EnableCaching
  6. public class SpringcacheDemoApplication
  7. {
  8. public static void main(String[] args)
  9. {
  10. SpringApplication.run(SpringcacheDemoApplication.class, args);
  11. }
  12. }

 

5、使用EhCache实现缓存管理

5.1 创建实体类(Entity层)

在com.pjb.entity包中,创建UserInfo类(用户信息实体类)。

  1. package com.pjb.entity;
  2. import java.io.Serializable;
  3. /**
  4. * 用户信息实体类
  5. * @author pan_junbiao
  6. **/
  7. public class UserInfo implements Serializable
  8. {
  9. private int userId; //用户编号
  10. private String userName; //用户姓名
  11. private int age; //年龄
  12. private String blogUrl; //博客地址
  13. private String blogRemark; //博客信息
  14. //省略getter与setter方法...
  15. }

注意:实体类必须实现 Serializable 接口,否则无法实现缓存功能。

5.2 数据库映射层(Mapper层)

在com.pjb.mapper包中,创建UserMapper接口(用户信息Mapper动态代理接口)。

  1. package com.pjb.mapper;
  2. import com.pjb.entity.UserInfo;
  3. import org.apache.ibatis.annotations.*;
  4. import org.springframework.stereotype.Repository;
  5. /**
  6. * 用户信息Mapper动态代理接口
  7. * @author pan_junbiao
  8. **/
  9. @Mapper
  10. @Repository
  11. public interface UserMapper
  12. {
  13. /**
  14. * 根据用户ID,获取用户信息
  15. */
  16. @Select("SELECT * FROM tb_user WHERE user_id = #{userId}")
  17. public UserInfo getUserById(int userId);
  18. /**
  19. * 新增用户,并获取自增主键
  20. */
  21. @Insert("INSERT INTO tb_user(user_name,age,blog_url,blog_remark) VALUES(#{userName},#{age},#{blogUrl},#{blogRemark});")
  22. @Options(useGeneratedKeys = true, keyColumn = "user_id", keyProperty = "userId")
  23. public int insertUser(UserInfo userInfo);
  24. /**
  25. * 修改用户
  26. */
  27. @Update("UPDATE tb_user SET user_name = #{userName} ,age = #{age} ,blog_url = #{blogUrl} ,blog_remark = #{blogRemark} WHERE user_id = #{userId}")
  28. public int updateUser(UserInfo userInfo);
  29. /**
  30. * 删除用户
  31. */
  32. @Delete("DELETE FROM tb_user WHERE user_id = #{userId}")
  33. public int deleteUser(int userId);
  34. }

5.3 业务逻辑层(Service层)

在com.pjb.service包下,创建UserService接口(用户信息业务逻辑接口)。

  1. package com.pjb.service;
  2. import com.pjb.entity.UserInfo;
  3. /**
  4. * 用户信息业务逻辑接口
  5. * @author pan_junbiao
  6. **/
  7. public interface UserService
  8. {
  9. /**
  10. * 根据用户ID,获取用户信息
  11. */
  12. public UserInfo getUserById(int userId);
  13. /**
  14. * 新增用户,并获取自增主键
  15. */
  16. public UserInfo insertUser(UserInfo userInfo);
  17. /**
  18. * 修改用户
  19. */
  20. public UserInfo updateUser(UserInfo userInfo);
  21. /**
  22. * 删除用户
  23. */
  24. public int deleteUser(int userId);
  25. }

在com.pjb.service.impl包下,创建UserServiceImpl类(用户信息业务逻辑类)。

  1. package com.pjb.service.impl;
  2. import com.pjb.entity.UserInfo;
  3. import com.pjb.mapper.UserMapper;
  4. import com.pjb.service.UserService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.cache.annotation.CacheConfig;
  7. import org.springframework.cache.annotation.CacheEvict;
  8. import org.springframework.cache.annotation.CachePut;
  9. import org.springframework.cache.annotation.Cacheable;
  10. import org.springframework.stereotype.Service;
  11. /**
  12. * 用户信息业务逻辑类
  13. * @author pan_junbiao
  14. **/
  15. //注意:必须对应配置文件ehcache.xml中cache节点的name属性值
  16. //@CacheConfig(cacheNames = "userCache")
  17. @Service
  18. public class UserServiceImpl implements UserService
  19. {
  20. @Autowired
  21. private UserMapper userMapper;
  22. //注意:必须对应配置文件ehcache.xml中cache节点的name属性值
  23. private static final String CACHE_NAME = "userCache";
  24. /**
  25. * 根据用户ID,获取用户信息
  26. */
  27. @Override
  28. @Cacheable(value = CACHE_NAME, key = "#userId")
  29. public UserInfo getUserById(int userId)
  30. {
  31. return userMapper.getUserById(userId);
  32. }
  33. /**
  34. * 新增用户,并获取自增主键
  35. */
  36. @Override
  37. @CachePut(value = CACHE_NAME, key = "#userInfo.userId")
  38. public UserInfo insertUser(UserInfo userInfo)
  39. {
  40. userMapper.insertUser(userInfo);
  41. return userInfo;
  42. }
  43. /**
  44. * 修改用户
  45. */
  46. @Override
  47. @CachePut(value = CACHE_NAME, key = "#userInfo.userId")
  48. public UserInfo updateUser(UserInfo userInfo)
  49. {
  50. userMapper.updateUser(userInfo);
  51. return userInfo;
  52. }
  53. /**
  54. * 删除用户
  55. */
  56. @Override
  57. @CacheEvict(value = CACHE_NAME, key = "#userId")
  58. public int deleteUser(int userId)
  59. {
  60. return userMapper.deleteUser(userId);
  61. }
  62. }

从上述代码可以看出,查询用户的方法使用了 @Cacheable 注解来开启缓存。添加和修改方法使用了 @CachePut 注解,它是先处理方法,然后把结果进行缓存的。要想删除数据,则需要使用 @CacheEvict 注解来清空缓存。

@CacheConfig注解:如果所有的 @Cacheable() 里面都有一个 value=“xxx” 的属性,这显然如果方法多了,写起来也是挺累的,如果可以一次性声明完 那就省事了,所以有了 @CacheConfig 这个配置,@CacheConfig is a class-level annotation that allows to share the cache names,如果你在方法写别的名字,那么依然以方法的名字为准。

5.4 控制器方法(Controller层)

在com.pjb.controller包中,创建UserController类(用户控制器),实现用户数据的查询、新增、修改、删除,并实现数据的返回。

  1. package com.pjb.controller;
  2. import com.pjb.entity.UserInfo;
  3. import com.pjb.service.UserService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.ResponseBody;
  8. import org.springframework.web.servlet.ModelAndView;
  9. /**
  10. * 用户信息控制器
  11. * @author pan_junbiao
  12. **/
  13. @Controller
  14. @RequestMapping("/user")
  15. public class UserController
  16. {
  17. @Autowired
  18. private UserService userService;
  19. /**
  20. * 获取用户信息
  21. */
  22. @RequestMapping("getUserById")
  23. public ModelAndView getUserById(int userId)
  24. {
  25. //根据用户ID,获取用户信息
  26. UserInfo userInfo = userService.getUserById(userId);
  27. if(userInfo==null)
  28. {
  29. userInfo = new UserInfo();
  30. }
  31. //返回结果
  32. ModelAndView modelAndView = new ModelAndView();
  33. modelAndView.addObject("userInfo",userInfo);
  34. modelAndView.setViewName("/user-info.html");
  35. return modelAndView;
  36. }
  37. /**
  38. * 新增用户
  39. */
  40. @ResponseBody
  41. @RequestMapping("insertUser")
  42. public boolean insertUser()
  43. {
  44. //创建新用户
  45. UserInfo userInfo = new UserInfo();
  46. userInfo.setUserName("pan_junbiao的博客");
  47. userInfo.setAge(32);
  48. userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");
  49. userInfo.setBlogRemark("您好,欢迎访问 pan_junbiao的博客");
  50. //执行新增方法
  51. userService.insertUser(userInfo);
  52. //返回结果
  53. return userInfo.getUserId() > 0 ? true : false;
  54. }
  55. /**
  56. * 修改用户
  57. */
  58. @ResponseBody
  59. @RequestMapping("updateUser")
  60. public boolean updateUser(int userId)
  61. {
  62. UserInfo userInfo = new UserInfo();
  63. userInfo.setUserId(userId);
  64. userInfo.setUserName("pan_junbiao的博客_02");
  65. userInfo.setAge(35);
  66. userInfo.setBlogUrl("https://blog.csdn.net/pan_junbiao");
  67. userInfo.setBlogRemark("您好,欢迎访问 pan_junbiao的博客");
  68. //执行修改方法
  69. userService.updateUser(userInfo);
  70. //返回结果
  71. return true;
  72. }
  73. /**
  74. * 删除用户
  75. */
  76. @ResponseBody
  77. @RequestMapping("deleteUser")
  78. public boolean deleteUser(int userId)
  79. {
  80. //执行新增方法
  81. int result = userService.deleteUser(userId);
  82. //返回结果
  83. return result > 0 ? true : false;
  84. }
  85. }

5.5 显示页面(View层)

在 resources/templates 目录下,创建 user-info.html 用户信息显示页面。

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>用户信息</title>
  6. <meta name="author" content="pan_junbiao的博客">
  7. <style>
  8. table { border-collapse: collapse; margin-bottom: 10px}
  9. table,table tr th, table tr td { border:1px solid #000000; padding: 5px 10px;}
  10. </style>
  11. </head>
  12. <body>
  13. <div align="center">
  14. <table>
  15. <caption>用户信息</caption>
  16. <tr>
  17. <th>用户ID:</th>
  18. <td th:text="${userInfo.userId}"></td>
  19. </tr>
  20. <tr>
  21. <th>用户名称:</th>
  22. <td th:text="${userInfo.userName}"></td>
  23. </tr>
  24. <tr>
  25. <th>年龄:</th>
  26. <td th:text="${userInfo.age}"></td>
  27. </tr>
  28. <tr>
  29. <th>博客地址:</th>
  30. <td th:text="${userInfo.blogUrl}"></td>
  31. </tr>
  32. <tr>
  33. <th>备注信息:</th>
  34. <td th:text="${userInfo.blogRemark}"></td>
  35. </tr>
  36. </table>
  37. </div>
  38. </body>
  39. </html>

至此,项目已经编写完成,执行结果如下图:

接着运行项目的其他方法,然后多次访问查询方法的URL,体验缓存效果。主要观察数据库是否进行了操作,如果数据库没有操作数据而正常返回数据,则代表缓存成功。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/929832
推荐阅读
相关标签
  

闽ICP备14008679号