引入依赖
在pom.xml
文件导入如下依赖:
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.6.13</version> <!--可以省略版本 由SpringBoot自动确定适配版本-->
</dependency>
配置Redis
配置Redis数据库参数
在application.properties
配置文件中,填写以下配置:
# RedisProperties
# 确定使用Redis的第11号数据库
spring.redis.database=11
# 配置Redis连接地址
spring.redis.host=localhost
# 配置Redis连接端口
spring.redis.port=6379
# 配置连接Redis的密码 Redis数据库无密码则不需要此配置
spring.redis.password=连接密码
配置结果如下图所示:
编写配置类,构造RedisTemplate
RedisConfig.class
配置类如下,用于获取RedisTemplate
类
/**
* @author 花木凋零成兰
* @date 2024/3/17 14:58
*/
@Configuration
public class RedisConfig {
/**
* 获取访问Redis模板类
* @param factory Redis连接工厂类 自动装配
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory); // 配置连接工厂
// 需要配置序列化方式 将Java类型数据存到Redis数据库中
// 设置 key 的序列化方式
template.setKeySerializer(RedisSerializer.string()); // RedisSerializer.string()序列字符串的序列化器
// 设置 value 的序列化方式
template.setValueSerializer(RedisSerializer.json()); // 序列化为json
// 设置 hash 的key的序列化方式
template.setHashKeySerializer(RedisSerializer.string());
// 设置 hash 的value的序列化方式
template.setHashValueSerializer(RedisSerializer.json());
// 使配置文件中的配置生效
template.afterPropertiesSet();
return template;
}
}
Redis操作
模板类常用方法操作如下:
操作字符串:
- redisTemplate.opsForValue()
操作哈希:
- redisTemplate.opsForHash()
操作列表:
- redisTemplate.opsForList()
操作集合(无序):
- redisTemplate.opsForSet()
操作集合(有序)
- redisTemplate.opsForZSet()
进行测试
测试代码如下:
/**
* @author 花木凋零成兰
* @date 2024/3/17 15:43
*/
@SpringBootTest
@ContextConfiguration(classes = Application.class) // 使用Application类的配置
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate; // 注入redisTemplate
@Test
public void testStrings() {
System.out.println("测试对字符串的操作...");
String redisKey = "test:count";
redisTemplate.opsForValue().set(redisKey, 1); // 存字符串数据
System.out.println(redisTemplate.opsForValue().get(redisKey)); // 获取key对应的value
System.out.println(redisTemplate.opsForValue().increment(redisKey)); // 自动增加key对应的value
System.out.println(redisTemplate.opsForValue().decrement(redisKey)); // 自动减少key对应的value
}
@Test
public void testHashes() {
System.out.println("测试对哈希的操作...");
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"));
}
@Test
public void testLists() {
System.out.println("测试对列表的操作...");
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));
}
@Test
public void testSets() {
System.out.println("测试对(无序)集合的操作...");
String redisKey = "test:teachers";
// 存set数据 可一次性存多个
redisTemplate.opsForSet().add(redisKey, "刘备", "关羽", "张飞", "赵云", "诸葛");
// 获取set中数据个数
System.out.println(redisTemplate.opsForSet().size(redisKey));
// 随机弹出set中的某个数据
System.out.println(redisTemplate.opsForSet().pop(redisKey));
// 展示set中的数据
System.out.println(redisTemplate.opsForSet().members(redisKey));
}
@Test
public void testSortedSets() {
System.out.println("测试对(有序)集合的操作...");
String redisKey = "test:students";
// 插入元素
redisTemplate.opsForZSet().add(redisKey, "唐僧", 80);
redisTemplate.opsForZSet().add(redisKey, "孙悟空", 90);
redisTemplate.opsForZSet().add(redisKey, "猪八戒", 70);
redisTemplate.opsForZSet().add(redisKey, "沙悟净", 75);
redisTemplate.opsForZSet().add(redisKey, "白龙马", 65);
// 统计数据个数
System.out.println(redisTemplate.opsForZSet().size(redisKey));
// 获取某个元素 的分数
System.out.println(redisTemplate.opsForZSet().score(redisKey, "猪八戒"));
// 获取某个元素 按大到小在集合的排名 的位置索引(从0开始)
System.out.println(redisTemplate.opsForZSet().reverseRank(redisKey, "猪八戒"));
// 获取元素 按大到小排名的 0-2个元素
System.out.println(redisTemplate.opsForZSet().reverseRange(redisKey, 0, 2));
}
@Test
public void testKeys() {
System.out.println("测试一些公共方法操作...");
redisTemplate.delete("test:user"); // 删除key所对的数据
// 判断key是否存在
System.out.println(redisTemplate.hasKey("test:user"));
// 设置某个key的过期时间
redisTemplate.expire("test:students", 10, TimeUnit.SECONDS);
}
}
测试结果如下所示:
优化redis多次访问同一个key
即将key绑定到一个对象上,不需要在每次对key所对应的value进行操作时,再传入key
实现代码如下:
@SpringBootTest
@ContextConfiguration(classes = Application.class) // 使用Application类的配置
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate; // 注入redisTemplate
@Test
public void testBoundOperations() {
System.out.println("多此访问同一个key; 将其绑定到一个对象, 即绑定对象...");
String redisKey = "test:count";
BoundValueOperations operations = redisTemplate.boundValueOps(redisKey); // 绑定key
// 接下来对同一个key进行操作 不需要再传入key
System.out.println(operations.get()); // 获取绑定的key 对应的值
// 对key所对应的value进行自增 5 次
operations.increment();
operations.increment();
operations.increment();
operations.increment();
operations.increment();
System.out.println(operations.get()); // 获取绑定的key 对应的值
}
}
测试结果如下:
Redis事务管理
redis事务机制:
启用事务后;执行某条redis命令时,不会立刻执行;而是将命令暂存到队列中,直到操作结束,提交事务时,再将队列中的所有命令发送给Redis,再执行队列中的命令.
编程式事务演示
在某个方法内的某部分代码,启用事务。
测试代码如下:
@SpringBootTest
@ContextConfiguration(classes = Application.class) // 使用Application类的配置
public class RedisTest {
// 编程式事务
@Test
public void testTransactional() {
Object obj = redisTemplate.execute(new SessionCallback() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
// redisTemplate.execute()方法调用时;底层自动调用该execute方法
// operations 用于执行操作命令
String redisKey = "test:text";
operations.multi(); // 启用事务
// 添加数据到set
operations.opsForSet().add(redisKey, "zhangsan", "lisi", "wangwu");
// 因为事务还未提交 即上述添加数据命令 还未执行
// 此时查看对应 set 集合中的数据 应该不存在上述添加数据
System.out.println(operations.opsForSet().members(redisKey));
return operations.exec(); // 提交事务 并结束方法调用
}
});
System.out.println("obj: " + obj); // 查看事务类型信息等
}
}
测试结果如下:
即由上述测试结果,证明了,redis事务是等到操作结束后,再执行队列中的命令;且事务得到的对象结果为[操作成功次数(一次添加数据成功数据个数),操作的数据]