课程内容
-
Redis入门
-
Redis数据类型
-
Redis常用命令
-
在Java中操作Redis
1. 前言
1.1 什么是Redis
redis是一款非关系型数据库,redis存储的数据是在内存中的。特点:可以快速读取到数据,因为存储的数据是在内存中的。Redis是一个基于内存的key-value结构数据库。Redis 是互联网技术领域使用最为广泛的存储中间件,它是「Remote Dictionary Service」的首字母缩写,也就是「远程字典服务」。
-
基于内存存储,读写性能高
-
适合存储热点数据(热点商品、资讯、新闻),一般数据一般变化频率比较低,或者是高并发请求数据
-
企业应用广泛
1.2 使用Redis能做什么
-
数据缓存
-
消息队列
-
注册中心
-
发布订阅
2. Redis入门
2.1 Redis简介
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker. 翻译为:Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。
官网:redis.io
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)。它存储的value类型比较丰富,也被称为结构化的NoSql数据库。
NoSql(Not Only SQL),不仅仅是SQL,泛指非关系型数据库。NoSql数据库并不是要取代关系型数据库,而是关系型数据库的补充。
关系型数据库(RDBMS):
-
Mysql
-
Oracle
-
DB2
-
SQLServer
非关系型数据库(NoSql):
-
Redis
-
Mongo db
-
MemCached
2.2 Redis下载与安装
2.2.1 Redis下载
Redis安装包分为windows版和Linux版:
-
Windows版下载地址:github.com/microsoftar…
-
Linux版下载地址: download.redis.io/releases/
下载后得到下面安装包:
2.2.2 Redis安装
1)在Linux中安装Redis
在Linux系统安装Redis步骤:
- 将Redis安装包上传到Linux到soft目录
- 解压安装包
cd /soft
tar -xvf redis-4.0.0.tar.gz -C /usr/local
- 因为已经自带了,可以不安装(安装Redis的依赖环境gcc,命令:yum install gcc-c++)
- 进入/usr/local/redis-4.0.0,进行编译,命令:make
cd /usr/local/redis-4.0.0
make
- 进入redis的src目录进行安装,命令:make install
cd src
make install
- 进入/usr/local/redis-4.0.0 ,把redis.conf文件拷贝到src目录中
# 现在src目录下,复制上一级的文件到当前目录下
cp ../redis.conf .
运行Redis
在src目录下:
./redis-server redis.conf
按ctrl+c退出redis服务器
以后台的方式执行Redis
- 修改redis.conf文件,让其在后台启动不要霸屏的方式启动,将配置文件中的daemonize配置项改为yes,默认值为no。用其它的文本编辑器也可以,修改redis.conf文件,136行,将no改成yes
daemonize yes
- redis默认是没有密码的,如果你需要有密码,将配置文件中的 # requirepass foobared 配置项取消注释,默认为注释状态。foobared为密码,可以根据情况自己指定。 (选做)
- 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
- redis的服务默认只是允许本机连接,其他机器默认情况是不被允许连接,如果允许其他机器也能连接linux的reids服务,那么需要修改bind 127.0.0.1 你自己的linux机器的ip地址
69行
bind 127.0.0.1 192.168.xxx.xxx
- 启动redis的服务
# 启动
./redis-server redis.conf
# 显示进程
ps -ef | grep redis
- 启动客户端去连接服务端测试: 启动客户端的方式:
-
-
方式一(没有密码方式): 在src目录中 ./redis-cli
-
-
方式二(如果存在密码情况): 在src目录中: ./redis-cli -h 127.0.0.1 -p 端口号 -a 密码
-
退出Redis
# 退出
./redis-cli shutdown
# 查看进程
ps -ef | grep redis
2)在Windows中安装Redis
Redis的Windows版属于绿色软件,直接解压即可使用,解压后目录结构如下:
2.3 Redis服务启动与停止
1)Linux系统中启动和停止Redis
执行Redis服务启动脚本文件redis-server:
通过启动日志可以看到,Redis默认端口号为6379。
Ctrl + C停止Redis服务
通过redis-cli可以连接到本地的Redis服务,默认情况下不需要认证即可连接成功。
退出客户端可以输入exit或者quit命令。
2)Windows系统中启动和停止Redis
在控制台执行redis-server redis.
Ctrl + C停止Redis服务
双击redis-cli.exe即可启动Redis客户端,默认连接的是本地的Redis服务,而且不需要认证即可连接成功。
退出客户端可以输入exit或者quit命令。
2.5 redis客户端程序
在今天的资料里面有redis的图形化界面工具,只需要双击不断下一步即可
连接redis服务器
3. Redis数据类型
3.1 介绍
Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种常用的数据类型:
-
字符串 string
-
哈希 hash
-
列表 list
-
集合 set
-
有序集合 sorted set / zset
3.2 Redis 5种常用数据类型
解释说明:
字符串(string):普通字符串,常用
哈希(hash):适合存储对象
列表(list):按照插入顺序排序,可以有重复元素
集合(set):无序集合,没有重复元素
有序集合(sorted set / zset):集合中每个元素关联一个分数(score),根据分数升序排序,没有重复元素
4. Redis常用命令
4.1 字符串string操作命令
Redis 中字符串类型常用命令:
-
SET key value 设置指定key的值
-
GET key 获取指定key的值
-
SETEX key seconds value 设置指定key的值,并将 key 的过期时间设为 seconds 秒
-
SETNX key value 只有在 key 不存在时设置 key 的值
更多命令可以参考Redis中文网:www.redis.net.cn
4.2 哈希hash操作命令
Redis hash 是一个string类型的 field 和 value 的映射表,hash特别适合用于存储对象,常用命令:
-
HSET key field value 将哈希表 key 中的字段 field 的值设为 value
-
HGET key field 获取存储在哈希表中指定字段的值
-
HDEL key field 删除存储在哈希表中的指定字段
-
HKEYS key 获取哈希表中所有字段
-
HVALS key 获取哈希表中所有值
-
HGETALL key 获取在哈希表中指定 key 的所有字段和值
命令演示
-
创建hash类型的键为user,并且添加一个字段为username,值为newboy
-
向user中添加字段为age,值为18
-
分别得到user中的username和age的字段值
-
向user中同时添加多个字段和值,birthday 2018-01-01 sex male
-
同时取得多个字段:age 和 sex
-
得到user中所有的字段和值
-
删除user中的生日和性别字段
4.3 列表list操作命令
Redis 列表是简单的字符串列表,按照插入顺序排序,常用命令:
-
LPUSH key value1 [value2] 将一个或多个值插入到列表头部
-
LRANGE key start stop 获取列表指定范围内的元素
-
RPOP key 移除并获取列表最后一个元素
-
LLEN key 获取列表长度
-
BRPOP key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
操作效果
4.4 集合set操作命令
Redis set 是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据,常用命令:
-
SADD key member1 [member2] 向集合添加一个或多个成员
-
SMEMBERS key 返回集合中的所有成员
-
SCARD key 获取集合的成员数
-
SINTER key1 [key2] 返回给定所有集合的交集
-
SUNION key1 [key2] 返回所有给定集合的并集
-
SDIFF key1 [key2] 返回给定所有集合的差集
-
SREM key member1 [member2] 移除集合中一个或多个成员
效果
创建两个集合:city和cities
4.5 有序集合sorted set操作命令
Redis sorted set 有序集合是 string 类型元素的集合,且不允许重复的成员。每个元素都会关联一个double类型的分数(score) 。redis正是通过分数来为集合中的成员进行从小到大排序。有序集合的成员是唯一的,但分数却可以重复。
常用命令:
-
ZADD key score1 member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的 分数
-
ZRANGE key start stop [WITHSCORES] 通过索引区间返回有序集合中指定区间内的成员
-
ZINCRBY key increment member 有序集合中对指定成员的分数加上增量 increment
-
ZREM key member [member ...] 移除有序集合中的一个或多个成员
操作
-
添加键country,分数是10,值是Japan
-
添加键country,分数是5,值是USA,添加键country,分数是50,值是Russian
-
添加键country,分数是1,值是China,分数是120,值是Korea
-
查询country中所有的元素
-
查询Japan的索引号(从0开始)
-
删除值为USA的元素
-
查询country中还有多少个元素
-
显示Russian的分数值
4.6 通用命令
Redis中的通用命令,主要是针对key进行操作的相关命令:
-
KEYS pattern 查找所有符合给定模式( pattern)的 key
-
EXISTS key 检查给定 key 是否存在
-
TYPE key 返回 key 所储存的值的类型
-
TTL key 返回给定 key 的剩余生存时间(TTL, time to live),以秒为单位
-
DEL key 该命令用于在 key 存在是删除 key
命令演示
-
显示所有的键
-
添加字符串man的值为Jack
-
从左边添加list的键是women,值是:Rose Mary Kate
-
添加一个字符串:person NewBoy
-
显示所有的键
-
一次删除women和man这两个键
-
分别判断person和women是否存在
-
分别判断person user myset mylist分别是什么类型
5. 在Java中操作Redis
5.1 介绍
前面我们讲解了Redis的常用命令,这些命令是我们操作Redis的基础,那么我们在java程序中应该如何操作Redis呢?这就需要使用Redis的Java客户端,就如同我们使用JDBC操作MySQL数据库一样。
Redis 的 Java 客户端很多,官方推荐的有三种:
-
Jedis
-
Lettuce
-
Redisson
Spring 对 Redis 客户端进行了整合,提供了 Spring Data Redis,在Spring Boot项目中还提供了对应的Starter,即 spring-boot-starter-data-redis。
5.2 Jedis
Jedis 是 Redis 的 Java 版本的客户端实现。
maven坐标:
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
使用 Jedis 操作 Redis 的步骤:
-
获取连接
-
执行操作
-
关闭连接
示例代码:
package com.itheima.test;
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class AppTest {
@Test
public void test01(){
//1. 获取redis连接的客户端对象
Jedis jedis = new Jedis("192.168.78.128",6379);
//2. 存储数据
jedis.set("name","狗娃");
//3. 获取数据
System.out.println("姓名:"+ jedis.get("name"));
//4. 关闭连接
jedis.close();
}
}
5.3 Spring Data Redis
5.3.1 介绍
Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
maven坐标:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.4.8</version>
</dependency>
Spring Boot提供了对应的Starter,maven坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Spring Data Redis中提供了一个高度封装的类:RedisTemplate,针对 Jedis 客户端中大量api进行了归类封装,将同一类型操作封装为Operation接口,具体分类如下:
-
ValueOperations:string类型,简单K-V操作
-
SetOperations:set类型数据操作
-
ZSetOperations:zset类型数据操作
-
HashOperations:针对hash类型的数据操作
-
ListOperations:针对list类型的数据操作
5.3.2 环境搭建
第一步: pom.xml
创建maven项目spring-data-redis-demo,配置pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>spring-data-redis-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<!-- 父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
</parent>
<dependencies>
<!-- 测试类 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.0</version>
</plugin>
</plugins>
</build>
</project>
第二步:编写启动类
package com.itheima;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class,args);
}
}
第三步:配置application.yml
spring:
redis:
# 可以指定Linux或Window下Redis服务器地址
host: 192.168.78.128
port: 6379
# password: 有密码你才写
database: 0 #redis默认有16个数据库, 操作的数据库是哪个
jedis:
pool:
max-active: 10 #最大链接数,连接池中最多有10个
max-idle: 5 # 最大空闲数,多余的释放
min-idle: 1 #最小空闲数
#举个例子:连接池初始化3个链接, 客户拿走2个链接,空闲1个,达到最小的空闲数,必须马上增加
max-wait: 200ms #连接池最大阻塞等待时间
解释说明:
spring.redis.database:指定使用Redis的哪个数据库,Redis服务启动后默认有16个数据库,编号分别是从0到15。
可以通过修改Redis配置文件来指定数据库的数量。
第四步:提供配置类
springdata_redis默认帮我们创建的RedisTemplate对象是使用jdk的序列号器帮我们键与值存储到redis中,而jdk的序列号器对键与值是采用二进制的方式存储的,所以我们会看到乱码的情况。如果我们需要看得懂,那么需要修改redistemplate使用的序列号器才行。
-
通过键使用字符串类型的序列化器:StringRedisSerializer
-
值使用JSON类型的序列化器:GenericJackson2JsonRedisSerializer
-
但因为在项目中LocalDateTime类型,GenericJackson2JsonRedisSerializer支持不理想,这里选择阿里巴巴的GenericFastJsonRedisSerializer,可以完美支持。
package com.itheima.config;
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
//创建模板对象
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//设置连接工厂
redisTemplate.setConnectionFactory(factory);
//设置键的序列化器:字符串的序列化器StringRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置值的序列化器:使用fastjson进行值的序列化器
redisTemplate.setValueSerializer(new GenericFastJsonRedisSerializer());
return redisTemplate;
}
}
解释说明:
Spring Boot 框架会自动装配 RedisTemplate 对象,但是需要注入RedisConnectionFactory对象,所有这个方法不能省略,默认的key序列化器为JdkSerializationRedisSerializer,导致我们存到Redis中后的数据和原始数据有差别。JdkSerializationRedisSerializer要求实体对象要有序列化接口Serializable。
第五步:提供测试类
package com.itheima.test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
public class RedisTest {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
}
5.3.3 操作String类型
set() 添加键和值
get() 获取值
setIfAbsent() 如果不存在这个键就添加
package com.itheima.test;
import com.itheima.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
@SpringBootTest
public class RedisTest {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 使用字符串类型
*/
@Test
public void testString() {
System.out.println("模板对象:" + redisTemplate);
//1. 获取字符串操作对象
ValueOperations opsForValue = redisTemplate.opsForValue();
//2. 添加字符串
opsForValue.set("book", "人鬼情喂鸟");
//3. 获取字符串
String book = (String) opsForValue.get("book");
System.out.println("书籍:" + book);
//4. 设置字符串,过期时间15秒
opsForValue.set("product","娃娃", 15, TimeUnit.SECONDS);
System.out.println("产品:" + opsForValue.get("product"));
//5. 如果不存在才添加
opsForValue.setIfAbsent("book", "西游记");
//获取字符串
book = (String) opsForValue.get("book");
System.out.println("书籍:" + book);
//6.添加的值是User对象
User user = new User(100, "孙悟空", LocalDateTime.now());
opsForValue.set("kong", user);
user = (User) opsForValue.get("kong");
System.out.println(user);
}
}
对象类型的序列化和反序列化
package com.itheima.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String name;
private LocalDateTime birthday;
}
Redis中内容
5.3.4 操作Hash类型数据
put() 添加键,字段,值
get() 通过键,字段获取值
keys() 获取所有的字段
values() 获取所有的值
entries() 获取所有的键和值
/**
* 使用hash类型
*/
@Test
public void testHash() {
//获取hash类型的操作对象
HashOperations<String, Object, Object> opsForHash = redisTemplate.opsForHash();
//添加三个值
opsForHash.put("user", "name", "张三");
opsForHash.put("user", "age", 20);
opsForHash.put("user", "sex", true);
//获取其中一个值
Object age = opsForHash.get("user", "age");
System.out.println("年龄:" + age);
//获取所有的键
Set<Object> keys = opsForHash.keys("user");
System.out.println(keys);
//获取所有的值
List<Object> values = opsForHash.values("user");
System.out.println(values);
//获取所有键和值
Map<Object, Object> user = opsForHash.entries("user");
System.out.println(user);
}
5.3.5 操作List类型数据
leftPushAll() 从左边添加多个元素
range() 获取指定范围所有的元素
size() 获取列表的长度
leftPop() 删除最左边的元素
/**
* 使用list类型
*/
@Test
public void testList() {
//获取操作列表的对象
ListOperations<String, Object> opsForList = redisTemplate.opsForList();
//添加多个元素到列表中
opsForList.leftPushAll("books", "红楼梦", "黑楼梦", "青楼梦");
//获取所有的元素
List<Object> books = opsForList.range("books", 0, -1);
System.out.println(books);
//获取元素个数
Long size = opsForList.size("books");
System.out.println("长度:" + size);
//删除最左边的元素
String book = (String) opsForList.leftPop("books");
System.out.println("删除的元素是:" + book);
}
5.3.6 操作Set类型数据
add() 添加一个或多个元素
members() 显示所有的成员
remove() 删除其中一个元素
/**
* 使用set类型
*/
@Test
public void testSet() {
SetOperations<String, Object> opsForSet = redisTemplate.opsForSet();
//添加多个元素
opsForSet.add("persons", "白骨精", "红骨精", "排骨精");
//获取所有的元素
Set<Object> persons = opsForSet.members("persons");
System.out.println(persons);
//删除其中一个元素
opsForSet.remove("persons", "排骨精");
}
5.3.7 操作ZSet类型
add() 添加一个或多个元素,同时指定值和分数
range() 获取指定范围的所有元素
incrementScore() 给某个元素加分
remove() 删除指定的元素
/**
* 使用zset类型
*/
@Test
public void testZset() {
ZSetOperations<String, Object> opsForZSet = redisTemplate.opsForZSet();
//添加元素
opsForZSet.add("cities", "上海", 3000);
opsForZSet.add("cities", "北京", 1000);
opsForZSet.add("cities", "广州", 5);
//获取所有的元素
Set<Object> cities = opsForZSet.range("cities", 0, -1);
System.out.println(cities);
//给北京加500
opsForZSet.incrementScore("cities", "北京", 500);
//删除指定的元素
opsForZSet.remove("cities", "上海");
}
5.3.8 通用操作
keys() 获取指定的键
delete() 删除键和值
hasKey() 判断是否存在某个键
type() 获取值的类型
/**
* 使用通用方法
*/
@Test
public void testOthers() {
//使用模板对象的方法
Set<String> keys = redisTemplate.keys("c*");
System.out.println(keys);
//删除指定的键和值
redisTemplate.delete("company");
//判断某个值是否存在
Boolean exists = redisTemplate.hasKey("cities");
System.out.println("键是否存在:" + exists);
//获取某个值的类型
DataType type = redisTemplate.type("country");
System.out.println("类型:" + type);
}