ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Spring Boot中使用缓存

Spring Boot中使用缓存 一、前言在程序中可以使用缓存的技术来节省对数据库的开销。Spring Boot对缓存提供了很好的支持我们几乎不用做过多的配置即可使用各种缓存实现。这里主要介绍平日里个人接触较多的Ehcache和Redis缓存实现。二、准备工作可根据《Spring Boot整合MyBatis》搭建一个Spring Boot项目然后yml中配置日志输出级别以观察SQL的执行情况logging:level:com:wno704:boot:mapper:DEBUG其中com.spring.mapper为MyBatis的Mapper接口路径。三、整合EhCache 缓存3.1 添加依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactId/dependency!-- spring-boot ehcache --dependencygroupIdnet.sf.ehcache/groupIdartifactIdehcache/artifactId/dependency3.2 添加配置1在 src/main/resources 目录下创建 ehcache.xml 文件内容如下?xml version1.0 encodingUTF-8?ehcachexmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:noNamespaceSchemaLocationhttp://ehcache.org/ehcache.xsd!-- 磁盘缓存位置 --diskStorepathjava.io.tmpdir/ehcache/!-- 默认缓存 --defaultCachemaxEntriesLocalHeap10000eternalfalsetimeToIdleSeconds120timeToLiveSeconds120maxEntriesLocalDisk10000000diskExpiryThreadIntervalSeconds120memoryStoreEvictionPolicyLRUpersistencestrategylocalTempSwap//defaultCache!-- 自定义缓存 --cachenamestudentmaxElementsInMemory1000eternalfalsetimeToIdleSeconds50timeToLiveSeconds50overflowToDiskfalsememoryStoreEvictionPolicyLRU//ehcache说明nameCache 的唯一标识maxElementsInMemory内存中允许存储的最大的元素个数maxElementsOnDisk硬盘最大缓存个数0代表无限个clearOnFlush内存数量最大时是否清除eternal缓存对象是否永久有效如果是超时设置将被忽略overflowToDisk内存不足超过 maxElementsInMemory时是否启用磁盘缓存timeToIdleSeconds设置对象在失效前的允许闲置时间单位秒。仅当eternalfalse对象不是永久有效时使用可选属性默认值是0也就是可闲置时间无穷大timeToLiveSeconds缓存数据的生存时间TTL也就是一个元素从构建到消亡的最大时间间隔值这只能在元素不是永久驻留时有效如果该值是0就意味着元素可以停顿无穷长的时间diskPersistent是否将缓存数据持久化到磁盘上如果为 trueJVM 重启数据依然存在。默认值是falsediskSpoolBufferSizeMB这个参数设置DiskStore磁盘缓存的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区diskExpiryThreadIntervalSeconds磁盘失效线程运行时间间隔默认是120秒memoryStoreEvictionPolicy当达到 maxElementsInMemory 限制时Ehcache 将根据指定策略清除内存。默认为 LRU最近最少使用其他策略有 FIFO先进先出LFU较少使用2修改application.yml spring:cache:#缓存类型ehcache、redistype:ehcacheehcache:config:classpath:ehcache.xml3)接着在Spring Boot入口类中加入EnableCaching注解开启缓存功能EnableCachingSpringBootApplicationpublicclassEhcacheApplication{publicstaticvoidmain(String[]args){SpringApplication.run(EhcacheApplication.class,args);}}3.3 编码在《Spring Boot整合MyBatis》的基础上结合 Mybatis 测试Service 层CacheConfig(cacheNamesstudent)publicinterfaceStudentService{CachePut(key#p0.sno)Studentsave(Studentstudent);CachePut(key#p0.sno)Studentupdate(Studentstudent);CacheEvict(key#p0,allEntriestrue)voiddeleteStudentBySno(intsno);Cacheable(key#p0)StudentqueryStudentBySno(intsno);}我们在StudentService接口中加入了CacheConfig注解queryStudentBySno方法使用了注解Cacheable(key“#p0”)即将id作为redis中的key值。当我们更新数据的时候应该使用CachePut(key“#p0.sno”)进行缓存数据的更新否则将查询到脏数据因为该注解保存的是方法的返回值所以这里应该返回Student。3.4 测试由于 ehcache 缓存是存储在应用的内存中如果使用 junit 测试方法执行完毕缓存就释放了无法正常测试缓存效果因此测试使用发起 http 请求的形式。发起查询请求Testpublicvoidtest1()throwsException{Studentstudent1this.studentService.queryStudentBySno(1);System.out.println(学号student1.getSno()的学生姓名为student1.getName());Studentstudent2this.studentService.queryStudentBySno(1);System.out.println(学号student2.getSno()的学生姓名为student2.getName());Studentstudent3this.studentService.queryStudentBySno(1);System.out.println(学号student3.getSno()的学生姓名为student3.getName());}结果2020-08-18 11:13:21.524 DEBUG 3156 --- [ main] c.w.b.m.StudentMapper.queryStudentBySno : Preparing: select * from student where sno? 2020-08-18 11:13:21.654 DEBUG 3156 --- [ main] c.w.b.m.StudentMapper.queryStudentBySno : Parameters: 1(Integer) 2020-08-18 11:13:21.679 DEBUG 3156 --- [ main] c.w.b.m.StudentMapper.queryStudentBySno : Total: 1 学号1的学生姓名为Mikle 学号1的学生姓名为Mikle 学号1的学生姓名为Mikle发起修改请求Testpublicvoidtest2()throwsException{Studentstudent1this.studentService.queryStudentBySno(1);System.out.println(学号student1.getSno()的学生姓名为student1.getName());student1.setName(康康);this.studentService.update(student1);Studentstudent2this.studentService.queryStudentBySno(1);System.out.println(学号student2.getSno()的学生姓名为student2.getName());Studentstudent3this.studentService.queryStudentBySno(1);System.out.println(学号student3.getSno()的学生姓名为student3.getName());}修改成功后立刻发起查询请求没有日志打印但返回修改后的对象数据说明缓存中的数据已经同步。2020-08-18 11:15:15.992 DEBUG 24212 --- [ main] c.w.b.m.StudentMapper.queryStudentBySno : Preparing: select * from student where sno? 2020-08-18 11:15:16.129 DEBUG 24212 --- [ main] c.w.b.m.StudentMapper.queryStudentBySno : Parameters: 1(Integer) 2020-08-18 11:15:16.155 DEBUG 24212 --- [ main] c.w.b.m.StudentMapper.queryStudentBySno : Total: 1 学号1的学生姓名为Mikle 2020-08-18 11:15:16.163 DEBUG 24212 --- [ main] c.w.boot.mapper.StudentMapper.update : Preparing: update student set sname?,ssex? where sno? 2020-08-18 11:15:16.166 DEBUG 24212 --- [ main] c.w.boot.mapper.StudentMapper.update : Parameters: 康康(String), M(String), 1(Integer) 2020-08-18 11:15:16.171 DEBUG 24212 --- [ main] c.w.boot.mapper.StudentMapper.update : Updates: 1 2020-08-18 11:15:16.172 DEBUG 24212 --- [ main] c.w.b.m.StudentMapper.queryStudentBySno : Preparing: select * from student where sno? 2020-08-18 11:15:16.172 DEBUG 24212 --- [ main] c.w.b.m.StudentMapper.queryStudentBySno : Parameters: 1(Integer) 2020-08-18 11:15:16.173 DEBUG 24212 --- [ main] c.w.b.m.StudentMapper.queryStudentBySno : Total: 1 学号1的学生姓名为康康 学号1的学生姓名为康康四、整合Redis缓存4.1 添加依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactId/dependency!-- spring-boot redis --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency4.2 配置1修改application.ymlspring:redis:# Redis服务器地址host:127.0.0.1# Redis服务器连接端口port:10007# Redis服务器连接密码password:2)接着在Spring Boot入口类中加入EnableCaching注解开启缓存功能EnableCachingSpringBootApplicationpublicclassEhcacheApplication{publicstaticvoidmain(String[]args){SpringApplication.run(EhcacheApplication.class,args);}}五、缓存注解CacheConfig主要用于配置该类中会用到的一些共用的缓存配置。在这里CacheConfig(cacheNames “student”)配置了该数据访问对象中返回的内容将存储于名为student的缓存对象中我们也可以不使用该注解直接通过Cacheable自己配置缓存集的名字来定义Cacheable配置了queryStudentBySno函数的返回值将被加入缓存。同时在查询时会先从缓存中获取若不存在才再发起对数据库的访问。该注解主要有下面几个参数value、cacheNames两个等同的参数cacheNames为Spring 4新增作为value的别名用于指定缓存存储的集合名。由于Spring 4中新增了CacheConfig因此在Spring 3中原本必须有的value属性也成为非必需项了key缓存对象存储在Map集合中的key值非必需缺省按照函数的所有参数组合作为key值若自己配置需使用SpEL表达式比如Cacheable(key “#p0”)使用函数第一个参数作为缓存的key值更多关于SpEL表达式的详细内容可参考https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#cache。condition缓存对象的条件非必需也需使用SpEL表达式只有满足表达式条件的内容才会被缓存比如Cacheable(key “#p0”, condition “#p0.length() 3”)表示只有当第一个参数的长度小于3的时候才会被缓存unless另外一个缓存条件参数非必需需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机该条件是在函数被调用之后才做判断的所以它可以通过对result进行判断keyGenerator用于指定key生成器非必需。若需要指定一个自定义的key生成器我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口并使用该参数来指定cacheManager用于指定使用哪个缓存管理器非必需。只有当有多个时才需要使用cacheResolver用于指定使用那个缓存解析器非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器并用该参数指定CachePut配置于函数上能够根据参数定义条件来进行缓存其缓存的是方法的返回值它与Cacheable不同的是它每次都会真实调用函数所以主要用于数据新增和修改操作上。它的参数与Cacheable类似具体功能可参考上面对Cacheable参数的解析CacheEvict配置于函数上通常用在删除方法上用来从缓存中移除相应数据。除了同Cacheable一样的参数之外它还有下面两个参数allEntries非必需默认为false。当为true时会移除所有数据eforeInvocation非必需默认为false会在调用方法之后移除数据。当为true时会在调用方法之前移除数据。六、缓存实现要使用上Spring Boot的缓存功能还需要提供一个缓存的具体实现。Spring Boot根据下面的顺序去侦测缓存实现Generic-JCache (JSR-107)-EhCache 2.x-Hazelcast-Infinispan-Redis-Guava-Simple除了按顺序侦测外我们也可以通过配置属性spring.cache.type来强制指定。
返回列表