使用Spring Data Redis实现数据缓存的方法
作者:JavaQ 发布时间:2021-08-02 10:19:25
引言
目前很多系统为了解决数据读写的性能瓶颈,在系统架构设计中使用Redis实现缓存,Spring框架为了让开发人员更加方便快捷的使用Redis实现缓存,对Redis的操作进行了包装。
0.缓存
个人理解的缓存是指用于存储频繁使用的数据的空间,关注点是存储数据的空间和使用频繁的数据。缓存技术,简单的说就是先从缓存中查询数据是否存在,存在则直接返回,不存在再执行相应的操作获取数据,并将获取的数据存储到缓存中,它是一种提升系统性能的重要方法。
1.Redis
Redis是一个开源的、内存存储key-value类型的数据结构服务器,可用作数据库、高速缓存和消息队列代理。它支持的数据类型有字符串、哈希表、列表、集合、有序集合等,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供分区功能。
2.jedis
jedis是Redis的Java版客户端实现,也是官方推荐的Java版客户端。它封装了对Redis的各种操作,并且支持事务、管道及有jedis自身实现的分布式。
3.Spring Data Redis
Spring Data是Spring框架中的一个主要项目,目的是为了简化构建基于Spring框架应用的数据访问,包括非关系数据库、Map-Reduce框架、云数据服务等,另外也包含对关系数据库的访问支持。
Spring Data Redis是Spring Data项目中的一个主要模块,实现了对jedis客户端API的高度封装,使对Redis的操作更加便捷。
4.关系图
Redis、jedis、Spring Data Redis三者之间的关系图如下所示。
5.Spring Cache
从Spring3.1开始,Spring框架提供了对Cache的支持,提供了一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的作用。提供的主要注解有@Cacheable、@CachePut、@CacheEvict和@Caching,具体见表1。
@Cacheable的常用属性及说明如表2所示。
@CacheEvict的常用属性见表4。@CachePut的常用属性同@Cacheable。
当需要在类上或方法上同时使用多个注解时,可以使用@Caching,如@Caching(cacheable = @Cacheable("User"), evict = {@CacheEvict("Member"), @CacheEvict(value = "Customer", allEntries = true)})
6.使用示例
下面使用Spring Data Reds、Redis和jedis实现一个简单的数据缓存。
1)依赖配置
示例使用了gradle,所以需要在build.gradle中加入如下依赖配置来管理所需要的jar。
compile "org.springframework.data:spring-data-redis:1.7.2.RELEASE"
compile "redis.clients:jedis:2.7.2"
testCompile "junit:junit:4.12"
2)Redis配置
示例连接的是本地的Redis,redis.properties配置如下。
# Redis settings
redis.host=127.0.0.1
redis.port=6379
redis.pass=
redis.dbIndex=0
redis.expiration=3000
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true
3)Spring配置
Spring的配置文件如下。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<context:component-scan base-package="redis.cache"/>
<context:annotation-config/>
<cache:annotation-driven cache-manager="redisCacheManager"/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:redis.properties</value>
</list>
</property>
</bean>
<!-- 配置JedisPoolConfig实例 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}"/>
<property name="maxTotal" value="${redis.maxActive}"/>
<property name="maxWaitMillis" value="${redis.maxWait}"/>
<property name="testOnBorrow" value="${redis.testOnBorrow}"/>
</bean>
<!-- 配置JedisConnectionFactory -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}"/>
<property name="port" value="${redis.port}"/>
<property name="password" value="${redis.pass}"/>
<property name="database" value="${redis.dbIndex}"/>
<property name="poolConfig" ref="poolConfig"/>
</bean>
<!-- 配置RedisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
</bean>
<!-- 配置RedisCacheManager -->
<bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg name="redisOperations" ref="redisTemplate"/>
<property name="defaultExpiration" value="${redis.expiration}"/>
</bean>
</beans>
4)Service
示例代码的Servicer如下。
@Service("userService")
public class UserService {
@Cacheable(value = "User", key = "'UserId_' + #id",condition = "#id<=110")
public String queryFullNameById(long id) {
System.out.println("execute queryFullNameById method");
return "ZhangSanFeng";
}
@CacheEvict(value = "User", key = "'UserId_' + #id")
public void deleteById(long id) {
System.out.println("execute deleteById method");
}
@CachePut(value = "User", key = "'UserId_' + #id")
public String modifyFullNameById(long id, String newName) {
System.out.println("execute modifyFullNameById method");
return newName;
}
}
5)测试
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("redisCacheContext.xml");
UserService userService = (UserService) context.getBean("userService");
System.out.println("第一次执行查询:" + userService.queryFullNameById(110L));
System.out.println("----------------------------------");
System.out.println("第二次执行查询:" + userService.queryFullNameById(110L));
System.out.println("----------------------------------");
userService.deleteById(110L);
System.out.println("----------------------------------");
System.out.println("清除缓存后查询:" + userService.queryFullNameById(110L));
System.out.println("----------------------------------");
System.out.println(userService.modifyFullNameById(110L, "ZhangJunBao"));
System.out.println("----------------------------------");
System.out.println("修改数据后查询:" + userService.queryFullNameById(110L));
System.out.println("----------------------------------");
System.out.println("第一次执行查询:" + userService.queryFullNameById(112L));
System.out.println("----------------------------------");
System.out.println("第二次执行查询:" + userService.queryFullNameById(112L));
System.out.println("----------------------------------");
}
6)测试结果
输出结果如下。
execute queryFullNameById method
第一次执行查询:ZhangSanFeng
----------------------------------
第二次执行查询:ZhangSanFeng
----------------------------------
execute deleteById method
----------------------------------
execute queryFullNameById method
清除缓存后查询:ZhangSanFeng
----------------------------------
execute modifyFullNameById method
ZhangJunBao
----------------------------------
修改数据后查询:ZhangJunBao
----------------------------------
execute queryFullNameById method
第一次执行查询:ZhangSanFeng
----------------------------------
execute queryFullNameById method
第二次执行查询:ZhangSanFeng
----------------------------------
从结果可以看到,使用缓存后,第二次查询没有执行查询方法体,直接返回了缓存中的数据;清除缓存后,再次查询就执行了查询方法体;修改数据后,相应的缓存数据也被修改了;不符合缓存条件的数据没有被缓存。
来源:https://www.jianshu.com/p/0dbe0a616898
猜你喜欢
- 这篇文章主要介绍了JDK线程池和Spring线程池的使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- 年前无意看到一个用Python写的小桌面程序,可以自动玩扫雷的游戏,觉得挺有意思,决定用C#也做一个。【真实情况
- 线程启动:1.start() 和 run()的区别说明start() : 它的作用是启动一个新线程,新线程会执行相应的run()方法。sta
- 前言相信很多Java开发都遇到过一个面试题:Resource和Autowired的区别是什么?这个问题的答案相信基本都清楚,但是这两者在Sp
- 示例 1 :使用搜索表单创建全屏模式我们要构建的小应用程序有一个应用程序栏,右侧有一个搜索按钮。按下此按钮时,将出现一个全屏模式对话框。它不
- ForkJoinTask就是ForkJoinPool里面的每一个任务。他主要有两个子类:RecursiveAction和RecursiveT
- 本文实例讲述了C#获取真实IP地址实现方法,分享给大家供大家参考。具体实现方法如下:通常来说,大家获取用户IP地址常用的方法是:string
- 今天是解决报错的一天,首先在操作Springboot中的时候,有些朋友的yml显示的不是绿叶的图标,或者是配置了之后不生效的问题。第一个解决
- 前言Kotlin一个强大之处就在于它的扩展函数,巧妙的运用这些扩展函数可以让你写出的代码更加优雅,阅读起来更加流畅,下面总结了在开发中经常用
- RocketMQ发送消息我们在使用RocketMQ发送消息时,一般都会使用DefaultMQProducer,类型的代码如下:Default
- 泛型在继承方面的体现类A是类B的父类,G<A>和G<B>二者不具有子父类关系,二者是并列关系@Test &
- 1. JAVA源文件的命名JAVA源文件名必须和源文件中所定义的类的类名相同。2. Package的命名Package名的第一部分应是小写A
- SpringBoot访问html和js等静态资源配置把静态资源放到resources/static下,这是springboot静态资源默认访
- Spring整合mybatis注解扫描是否成功IDEA spring整合mybatis会使用注解扫描的配置<context:compo
- 在后台工程师开发完新代码交给QA进行测试时,软件测试人员一般都会要求后台开发对单元测试的覆盖率达到一定的标准;例如我们的标准是分支覆盖率达到
- 首先是.select在MP查询中,默认查询所有的字段,如果有需要也可以通过select方法进行指定字段。其中要注意的细节:wrapper.s
- 这篇文章主要介绍了如何使用两个栈实现队列Java,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以
- 在每一个窗体生成的时候,都会针对于当前的窗体定义InitializeComponent()方法,该方法实际上是由系统生成的对于窗体界面的定义
- 一、添加pom.xml依赖<parent> <groupId>org.springfram
- @Order控制配置类/AOP/方法/字段的加载顺序1.AOP加载顺序 @Component &nbs