1. Redis简介
Redis是一个基于内存的key-value结构数据库。Redis 是互联网技术领域使用最为广泛的存储中间件。
官网:https://redis.io
中文网:Redis中文网
2. Redis下载与安装
2.1 Redis下载
Redis安装包分为windows版和Linux版:
-
Windows版下载地址:https://github.com/microsoftarchive/redis/releases
-
Linux版下载地址: https://download.redis.io/releases/
2.2 Redis安装
2.2.1 Windows中
Redis的Windows版属于绿色软件,直接解压即可使用,解压后目录结构如下:
2.2.2 Linux中
-
将Redis安装包上传到Linux
-
解压安装包,命令:tar -zxvf redis-4.0.0.tar.gz -C /usr/local
-
安装Redis的依赖环境gcc,命令:yum install gcc-c++
-
进入/usr/local/redis-4.0.0,进行编译,命令:make
-
进入redis的src目录进行安装,命令:make install
安装后重点文件说明:
-
/usr/local/redis-4.0.0/src/redis-server:Redis服务启动脚本
-
/usr/local/redis-4.0.0/src/redis-cli:Redis客户端脚本
-
/usr/local/redis-4.0.0/redis.conf:Redis配置文件
3. Spring Data Redis使用
3.1 介绍
在java程序中应该如何操作Redis呢?这就需要使用Redis的Java客户端,就如同我们使用JDBC操作MySQL数据库一样。
Spring 对 Redis 客户端进行了整合,提供了 Spring Data Redis,在Spring Boot项目中还提供了对应的Starter,即 spring-boot-starter-data-redis。
Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
网址:https://spring.io/projects/spring-data-redis
Spring Data Redis中提供了一个高度封装的类:RedisTemplate,对相关api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:
-
ValueOperations:string数据操作
-
SetOperations:set类型数据操作
-
ZSetOperations:zset类型数据操作
-
HashOperations:hash类型的数据操作
-
ListOperations:list类型的数据操作
3.2 环境搭建
3.2.1 导入maven坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3.2.2 配置Redis数据源
在application.yml中添加:
spring:
redis:
host: 地址
port: 6379
password: 123456
database: 8
解释说明:
database:指定使用Redis的哪个数据库,Redis服务启动后默认有16个数据库,编号分别是从0到15。可以通过修改Redis配置文件来指定数据库的数量。
3.2.3 编写配置类,创建RedisTemplate对象
@Configuration
@Slf4j
public class RedisConfiguration {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
log.info("开始创建redis模板对象...");
RedisTemplate redisTemplate = new RedisTemplate();
//设置redis的连接工厂对象
redisTemplate.setConnectionFactory(redisConnectionFactory);
//设置redis key的序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
解释说明:
当前配置类不是必须的,因为 Spring Boot 框架会自动装配 RedisTemplate 对象,但是默认的key序列化器为JdkSerializationRedisSerializer,导致我们存到Redis中后的数据和原始数据有差别,故设置为StringRedisSerializer序列化器。
3.2.4 通过RedisTemplate对象操作Redis
下面测试类中进行了简单的测试:
@SpringBootTest
public class SpringDataRedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testRedisTemplate(){
System.out.println(redisTemplate);
//string数据操作
ValueOperations valueOperations = redisTemplate.opsForValue();
//hash类型的数据操作
HashOperations hashOperations = redisTemplate.opsForHash();
//list类型的数据操作
ListOperations listOperations = redisTemplate.opsForList();
//set类型数据操作
SetOperations setOperations = redisTemplate.opsForSet();
//zset类型数据操作
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
}
}
测试通过,说明RedisTemplate对象注入成功,并且通过该RedisTemplate对象获取操作5种数据类型相关对象。
3.3 使用示例
3.3.1 操作字符串类型数据
/**
* 操作字符串类型的数据
*/
@Test
public void testString(){
// 使用 redisTemplate 的 opsForValue() 操作字符串类型的数据
// 1. 使用 set() 方法设置键为 "name",值为 "小明"
redisTemplate.opsForValue().set("name", "小明");
// 2. 使用 get() 方法获取键为 "name" 的值,类型为 String
// 由于 redisTemplate 返回的值是 Object 类型,因此这里需要强制转换为 String 类型
String city = (String) redisTemplate.opsForValue().get("name");
// 3. 输出获取到的值 "name" 对应的内容,即 "小明"
System.out.println(city);
// 4. 使用 set() 方法设置键为 "code",值为 "1234",并且设置该键 3 分钟后过期
// 参数说明:
// 第一个参数是键(key),这里为 "code"
// 第二个参数是值(value),这里为 "1234"
// 第三个参数是过期时间,这里为 3
// 第四个参数是时间单位,这里为分钟(TimeUnit.MINUTES)
redisTemplate.opsForValue().set("code", "1234", 3, TimeUnit.MINUTES);
// 5. 使用 setIfAbsent() 方法尝试设置键为 "lock" 的值为 "1",如果键不存在则设置成功
// setIfAbsent() 方法等同于 Redis 的 SETNX(Set if Not eXists)操作
// 如果 "lock" 不存在,设置值为 "1" 并返回 true;如果 "lock" 已经存在,返回 false
redisTemplate.opsForValue().setIfAbsent("lock", "1");
// 6. 再次尝试使用 setIfAbsent() 设置键为 "lock" 的值为 "2",但因为上一步已经设置了 "lock" 键的值,所以这次不会成功
// 由于 "lock" 键已经存在,setIfAbsent() 不会修改它的值,返回 false
redisTemplate.opsForValue().setIfAbsent("lock", "2");
}
3.3.2 操作哈希类型数据
/**
* 操作哈希类型的数据
*/
@Test
public void testHash(){
// 使用 redisTemplate 的 opsForHash() 来操作哈希类型数据
HashOperations hashOperations = redisTemplate.opsForHash();
// 1. 使用 put() 方法向哈希表 "100" 中添加键值对 "name"-"tom"
// 这里 "100" 是哈希表的 key,"name" 是哈希表中字段的 key,"tom" 是对应的 value
hashOperations.put("100", "name", "tom");
// 2. 使用 put() 方法向哈希表 "100" 中添加键值对 "age"-"20"
// "100" 是哈希表的 key,"age" 是字段的 key,"20" 是字段的值
hashOperations.put("100", "age", "20");
// 3. 使用 get() 方法从哈希表 "100" 中获取字段 "name" 对应的值
// 这里获取的是哈希表 "100" 中字段 "name" 的值,返回的是 Object 类型
String name = (String) hashOperations.get("100", "name");
// 4. 输出获取到的字段 "name" 的值,即 "tom"
System.out.println(name);
// 5. 使用 keys() 方法获取哈希表 "100" 中的所有字段名称
// 该方法返回哈希表中所有字段的 key 值,类型为 Set
Set keys = hashOperations.keys("100");
// 6. 输出哈希表 "100" 中的所有字段名称
System.out.println(keys);
// 7. 使用 values() 方法获取哈希表 "100" 中所有字段的值
// 该方法返回哈希表中所有字段的值,类型为 List
List values = hashOperations.values("100");
// 8. 输出哈希表 "100" 中的所有字段值
System.out.println(values);
// 9. 使用 delete() 方法删除哈希表 "100" 中的字段 "age"
// 这里 "100" 是哈希表的 key,"age" 是要删除的字段的 key
hashOperations.delete("100", "age");
}
3.3.3 操作列表类型数据
/**
* 操作列表类型的数据
*/
@Test
public void testList(){
// 使用 redisTemplate 的 opsForList() 方法获取操作列表类型数据的工具
ListOperations listOperations = redisTemplate.opsForList();
// 1. 使用 leftPushAll() 方法,将多个元素 "a", "b", "c" 依次从左边推入列表 "mylist"
// "mylist" 是 Redis 中的 key,元素 "a", "b", "c" 将按顺序推入列表左端
listOperations.leftPushAll("mylist", "a", "b", "c");
// 2. 使用 leftPush() 方法,将元素 "d" 从左边推入列表 "mylist"
// 这个操作会使得 "d" 位于列表最左端,顺序为 ["d", "a", "b", "c"]
listOperations.leftPush("mylist", "d");
// 3. 使用 range() 方法获取列表 "mylist" 中指定范围的元素
// 参数 0 表示起始索引,-1 表示结束索引(-1 代表列表的最后一个元素)
// 该操作会返回整个列表中的所有元素
List mylist = listOperations.range("mylist", 0, -1);
// 4. 输出列表 "mylist" 的所有元素
System.out.println(mylist); // 输出结果为 ["d", "a", "b", "c"]
// 5. 使用 rightPop() 方法从右边移除列表 "mylist" 的最后一个元素
// 此操作会移除元素 "c",使得列表变为 ["d", "a", "b"]
listOperations.rightPop("mylist");
// 6. 使用 size() 方法获取列表 "mylist" 的长度(元素个数)
// 此时列表的长度应为 3,因为移除了一个元素
Long size = listOperations.size("mylist");
// 7. 输出列表 "mylist" 的长度
System.out.println(size); // 输出结果为 3
}
3.3.4 操作集合类型数据
/**
* 操作集合(Set)类型的数据
*/
@Test
public void testSet(){
// 使用 redisTemplate 的 opsForSet() 方法获取操作集合类型数据的工具
SetOperations setOperations = redisTemplate.opsForSet();
// 1. 使用 add() 方法向集合 "set1" 中添加元素 "a", "b", "c", "d"
// Redis 中的集合类型不允许重复元素,这里 "set1" 是 Redis 中的一个集合 key
setOperations.add("set1", "a", "b", "c", "d");
// 2. 向另一个集合 "set2" 中添加元素 "a", "b", "x", "y"
// "set2" 是 Redis 中的另一个集合 key,元素 "a" 和 "b" 在两个集合中都有,形成交集
setOperations.add("set2", "a", "b", "x", "y");
// 3. 使用 members() 方法获取集合 "set1" 中的所有元素
// 此操作返回集合中的所有成员,集合的顺序是无序的
Set members = setOperations.members("set1");
// 4. 输出集合 "set1" 中的所有元素
System.out.println(members); // 可能输出为 [a, b, c, d]
// 5. 使用 size() 方法获取集合 "set1" 的元素个数
Long size = setOperations.size("set1");
// 6. 输出集合 "set1" 的大小
System.out.println(size); // 输出结果应为 4
// 7. 使用 intersect() 方法获取集合 "set1" 和集合 "set2" 的交集
// 交集是两个集合中共同存在的元素,此操作返回交集中的元素
Set intersect = setOperations.intersect("set1", "set2");
// 8. 输出两个集合的交集
System.out.println(intersect); // 可能输出为 [a, b]
// 9. 使用 union() 方法获取集合 "set1" 和集合 "set2" 的并集
// 并集是两个集合中的所有元素,此操作返回并集中所有不重复的元素
Set union = setOperations.union("set1", "set2");
// 10. 输出两个集合的并集
System.out.println(union); // 可能输出为 [a, b, c, d, x, y]
// 11. 使用 remove() 方法从集合 "set1" 中移除指定的元素 "a" 和 "b"
// 此操作会将 "a" 和 "b" 从 "set1" 中删除
setOperations.remove("set1", "a", "b");
}
3.3.5 操作有序集合类型数据
/**
* 操作有序集合(ZSet)类型的数据
*/
@Test
public void testZset(){
// 使用 redisTemplate 的 opsForZSet() 方法获取操作有序集合类型数据的工具
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
// 1. 使用 add() 方法向有序集合 "zset1" 中添加元素 "a" 并设置其分数为 10
// Redis 中的 ZSet 是有序集合,它的每个元素都有一个分数,元素按分数从小到大排序
zSetOperations.add("zset1", "a", 10);
// 2. 向有序集合 "zset1" 中添加元素 "b",分数为 12
zSetOperations.add("zset1", "b", 12);
// 3. 向有序集合 "zset1" 中添加元素 "c",分数为 9
zSetOperations.add("zset1", "c", 9);
// 4. 使用 range() 方法获取有序集合 "zset1" 中所有元素
// 参数 (0, -1) 表示获取从第 0 位到最后一位的所有元素,集合按分数从小到大排序
Set zset1 = zSetOperations.range("zset1", 0, -1);
// 5. 输出集合 "zset1" 中的所有元素,按分数升序排列
System.out.println(zset1); // 可能输出为 [c, a, b],根据分数排序
// 6. 使用 incrementScore() 方法为有序集合 "zset1" 中的元素 "c" 的分数增加 10
// 元素 "c" 的原分数为 9,增加后变为 19
zSetOperations.incrementScore("zset1", "c", 10);
// 7. 使用 remove() 方法从有序集合 "zset1" 中删除指定的元素 "a" 和 "b"
// 此操作会将元素 "a" 和 "b" 从集合中移除
zSetOperations.remove("zset1", "a", "b");
}
3.3.6 通用命令操作
/**
* 通用命令操作
*/
@Test
public void testCommon(){
// 使用 redisTemplate 的 keys() 方法获取所有键(key),支持通配符 "*"
// 例如, "*" 获取所有键,"user*" 可以获取所有以 "user" 开头的键
Set keys = redisTemplate.keys("*");
// 输出当前 Redis 数据库中所有的键
System.out.println(keys);
// 使用 hasKey() 方法检查 Redis 中是否存在键 "name"
Boolean name = redisTemplate.hasKey("name");
// 检查键 "set1" 是否存在
Boolean set1 = redisTemplate.hasKey("set1");
// 遍历所有获取到的键
for (Object key : keys) {
// 使用 type() 方法获取每个键对应的值类型,如 String、Hash、List、Set、ZSet 等
DataType type = redisTemplate.type(key);
// 输出键的类型名称
System.out.println(type.name());
}
// 使用 delete() 方法删除键 "mylist" 及其对应的值
redisTemplate.delete("mylist");
}