文章目录
- 利用Spring整合Redis
- 引入依赖
- 配置Redis
- 访问Redis
- String类型数据
- Hash类型数据
- List类型数据
- Set类型数据
- SortedSort类型数据
- 全局key
- 简化多次访问同一个key情况代码
- Redis中的事务
- 核心方法execute()
- 事务代码实例
- 参考文献
利用Spring整合Redis
引入依赖
spring-boot-starter-data-redis
<dependency org="org.springframework.boot" name="spring-boot-starter-data-redis" rev="3.2.2"/><!-- 子pom版本: <version>xxx</version> -->
<!-- springboot或spring整合的包可以不用写子pom版本,
当前pom继承于某个父pom,父pom中声明了常用包的版本,这些版本做过测试,是兼容的,不容易出错 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
配置Redis
-
配置数据库参数
# RedisProperties # 选择使用redis的16个库中的一个 spring.redis.database=11 # 访问库的ip spring.redis.host=localhost # 访问redis端口,redis默认端口为6379 spring.redis.port=6379
-
编写配置类,构造核心组件RedisTemplate
springboot已经配置好了RedisTemplate,它在配置时将key做成了Object类型,更通用。但实际上我们在用时,key都是String类型,因此默认的配置类用起来不方便,我们最好重新做一个配置
// 标明配置类 @Configuration public class RedisConfig {// 配置RedisTemplate,以后可通过该对象访问redis// 装配返回值到容器中@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {// 利用template访问redis数据库时,需要创建连接,而连接是由连接工厂创建的,故需要把连接工厂注入给template// 当我们定义一个bean时,方法上有RedisConnectionFactory这样的参数,spring容器会自动把它注入进来,即这个bean已经被容器装配了RedisTemplate<String, Object> template = new RedisTemplate<>();// 令template具有访问数据库的能力:把连接工厂注入给templatetemplate.setConnectionFactory(factory);// template配置:主要配序列化方式,用于将java语言转换为redis的key-value形式// 设置key的序列化方式// RedisSerializer类中有统一的序列化方式,我们可以直接访问// RedisSerializer.string()返回一个能够将数据序列化为字符串的序列化器template.setKeySerializer(RedisSerializer.string());// 设置value的序列化方式:// value可以是各种形式的数据,序列化为json格式,因为json数据是结构化的,恢复回来很好读取很好识别template.setValueSerializer(RedisSerializer.json());// hash比较特殊,因为hash中的数据也是以key-value形式存储,也需要序列化// 设置hash的key的序列化方式template.setHashKeySerializer(RedisSerializer.string());// 设置hash的value的序列化方式template.setHashValueSerializer(RedisSerializer.json());// 配置完后,触发一下,令template中配置生效template.afterPropertiesSet();return template;}}
访问Redis
利用配置好的RedisTemplate对象,对redis进行操作
哪需要访问redis,就将RedisTemplate注入到哪
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class RedisTests {@Autowiredprivate RedisTemplate redisTemplate;.... ...}
通过redisTemplate调用opsForXXX()方法,方法的返回对象可以用来操作不同类型的数据
- 访问String类型数据:redisTemplate.opsForValue()
- 访问Hash类型数据:redisTemplate.opsForHash()
- 访问List类型数据:redisTemplate.opsForList()
- 访问Set类型数据:redisTemplate.opsForSet()
- 访问SortedSort类型数据:redisTemplate.opsForZSet()
ops为operations的缩写
String类型数据
// 操作redis中String类型数据@Testpublic void testStrings() {// 声明一个keyString redisKey = "test:count";// redisTemplate.opsForValue():String类型数据// 存String类型数据redisTemplate.opsForValue().set(redisKey, 1);// 取System.out.println(redisTemplate.opsForValue().get(redisKey));// 自增(redis中命令是简写,java中方法是全称)System.out.println(redisTemplate.opsForValue().increment(redisKey));// 自减System.out.println(redisTemplate.opsForValue().decrement(redisKey));}
Hash类型数据
// 操作redis中哈希类型数据@Testpublic void testHashes() {String redisKey = "test:user";// 存redisTemplate.opsForHash().put(redisKey, "id", 1);redisTemplate.opsForHash().put(redisKey, "username", "zhangsan");// 取System.out.println(redisTemplate.opsForHash().get(redisKey, "id"));System.out.println(redisTemplate.opsForHash().get(redisKey, "username"));}
List类型数据
// 操作redis中列表类型数据@Testpublic void testLists() {String redisKey = "test:ids";// 从左边存放redisTemplate.opsForList().leftPush(redisKey, 101);redisTemplate.opsForList().leftPush(redisKey, 102);redisTemplate.opsForList().leftPush(redisKey, 103);// 获取数据个数System.out.println(redisTemplate.opsForList().size(redisKey));// 获取索引位置处的数据System.out.println(redisTemplate.opsForList().index(redisKey, 0));// 获取某个索引范围内的数据System.out.println(redisTemplate.opsForList().range(redisKey, 0, 2));// 从左边开始取出一个数据System.out.println(redisTemplate.opsForList().leftPop(redisKey));System.out.println(redisTemplate.opsForList().leftPop(redisKey));System.out.println(redisTemplate.opsForList().leftPop(redisKey));}
Set类型数据
// 操作redis中集合类型数据@Testpublic void testSets() {String redisKey = "test:teachers";// 给集合中存数据redisTemplate.opsForSet().add(redisKey, "刘备", "关羽", "张飞", "赵云", "诸葛亮");// 集合中元素个数System.out.println(redisTemplate.opsForSet().size(redisKey));// 随机弹出一个元素System.out.println(redisTemplate.opsForSet().pop(redisKey));// 查看集合中元素System.out.println(redisTemplate.opsForSet().members(redisKey));}
SortedSort类型数据
// 操作redis中有序集合类型数据@Testpublic void testSortedSets() {String redisKey = "test:students";// 存数据redisTemplate.opsForZSet().add(redisKey, "唐僧", 80);redisTemplate.opsForZSet().add(redisKey, "悟空", 90);redisTemplate.opsForZSet().add(redisKey, "八戒", 50);redisTemplate.opsForZSet().add(redisKey, "沙僧", 70);redisTemplate.opsForZSet().add(redisKey, "白龙马", 60);// 有序集合中元素个数System.out.println(redisTemplate.opsForZSet().zCard(redisKey));// 查询元素的分数System.out.println(redisTemplate.opsForZSet().score(redisKey, "八戒"));// 查询指定元素正序排名(默认由小到大)System.out.println(redisTemplate.opsForZSet().rank(redisKey, "八戒"));// 查询指定元素反序排名(由大到小)System.out.println(redisTemplate.opsForZSet().reverseRank(redisKey, "八戒"));// 查询指定排名范围内数据(正,反序)System.out.println(redisTemplate.opsForZSet().range(redisKey, 0, 2));System.out.println(redisTemplate.opsForZSet().reverseRange(redisKey, 0, 2));}
全局key
// 操作redis中的key(公共命令)
@Test
public void testKeys() {// 删除keyredisTemplate.delete("test:user");// 判断key是否存在System.out.println(redisTemplate.hasKey("test:user"));// 设置key过期时间redisTemplate.expire("test:students", 10, TimeUnit.SECONDS);// keys命令在程序中不常用,通常都是去redis数据库中查的时候用
}
简化多次访问同一个key情况代码
// 多次访问同一个key,可以简化不停传入key的操作// 方法:将key绑定到一个对象上@Testpublic void testBoundOperations() {String redisKey = "test:count";// BoundXXXOperations: XXX为要访问的数据类型,redisTemplates可将key绑定到该对象上BoundValueOperations operations = redisTemplate.boundValueOps(redisKey);// 累加操作,不用再传入key了operations.increment();operations.increment();operations.increment();operations.increment();operations.increment();// 获取System.out.println(operations.get());}
Redis中的事务
关系型数据库需要严格遵守ACID,而非关系型数据库不完全满足ACID四个特性
启用事务后,当redis收到命令时,不会立刻执行,而是放到队列里存着,直到提交事务时,才将队列中的命令批量执行
因此,在事务中不要查询数据,会无效,因此要么在事务前查,要么事务提交后查
redis支持声明式事务和编程式事务,但通常不用声明式事务
因为声明式事务只能精确到一个方法上(即给一个方法加上注解,将整个方法看作一个事务),这样的话,方法内部就无法进行查询了
通常用编程式事务将事务范围缩小
核心方法execute()
Redis 进行批量操作,可以使用 RedisTemplate 的 execute()方法。
execute() 方法,可以在一次连接中进行多个命令操作,执行完会自动关闭连接。
execute() 需要传入一个回调接口作为参数,SessionCallback参数 和 RedisCallback参数
SessionCallback 比 RedisCallck 更好些,优先使用 SessionCallback 。
使用SessionCallback , 还可以配合multi() 和 watch() 进行事务操作。
事务代码实例
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class RedisTests {@Autowiredprivate RedisTemplate redisTemplate;// 编程式事务@Testpublic void testTransaction() {Object result = redisTemplate.execute(new SessionCallback() {// 在外层execute方法被调用时,底层自动调用匿名回调接口内的execute方法// 调用时会将执行命令的对象(RedisOperations)传入,利用这个对象来执行命令、管理事务// 返回的数据会返回到外层execute中,我们可以从外层execute方法上接收@Overridepublic Object execute(RedisOperations redisOperations) throws DataAccessException {// 事务之外// 定义key tx为transaction事务的缩写String redisKey = "text:tx";// 事务:启用-ti'jiao// 启用事务redisOperations.multi();// 在事务中进行操作redisOperations.opsForSet().add(redisKey, "zhangsan");redisOperations.opsForSet().add(redisKey, "lisi");redisOperations.opsForSet().add(redisKey, "wangwu");// 在事务中查询没有效果,因为命令在队列里存着,直到提交事务时,批量执行System.out.println(redisOperations.opsForSet().members(redisKey));// 提交事务return redisOperations.exec();}});System.out.println(result);}}
参考文献
https://blog.csdn.net/sinat_32502451/article/details/133026414
存着,直到提交事务时,批量执行
System.out.println(redisOperations.opsForSet().members(redisKey));
// 提交事务return redisOperations.exec();}});System.out.println(result);
}
}
# 参考文献https://blog.csdn.net/sinat_32502451/article/details/133026414https://blog.csdn.net/qulinchao/article/details/122190636