【Redis】redis入门保姆教程
数据库分类
- 关系数据库(Sql):mysql,sqlserver;存放在硬盘中,查询的的时候是通过io操作。
- 非关系数据库(NoSql):Redis(持久化机制。淘汰策略),数据存放在内存中,因此也叫内存数据库。
- jvm内置缓存框架:EH cache 、OS cache
Sql与NoSql
sql:关系型数据库 NoSql:非关系型数据库
- 结构化:所有的字段与值之间具有强烈的约束关系,比如n个值只能对应一个表头的key 而NoSql是非结构化:拿Redis举例子,数据以key-value的形式保存,并且key可以封装成json对象,此外每一条json对象之间的key允许重复,因此没有强烈的约束关系。
- 关联:关系型数据库表与表之间可以通过外键进行关联,而Nosql的数据存储是通过json对象嵌套实现的,数据库本身不会去关联某个json对象,需要程序员自己去实现关联。
Redis特性:
Redis持久化机制好在哪里?
Redis可以把数据持久化,缓存到硬盘里,这样假如Redis宕机了,只需要重启Redis,可以从硬盘中恢复数据。
Redis的特性:分布式共享
在以前的老项目中使用到的jvm内置缓存框架,假如有多个服务器做集群的情况下,每一个jvm缓存,都会缓存一份,有一个缓存数据进行修改了,那么其他的缓存的数据也要跟着修改。而Redis的分布式管理,所有的服务器的数据都会放入Redis,保证了两台服务器的同步性。所以这也是为什么Redis支持分布式共享。
Redis的应用场景
- Token令牌的生成
- 短信验证码的code作为key存入Redis
- 实现缓存查询数据,减轻数据库访问压力(数据库底层是io操作,频繁访问数据库,执行效率性能低)
- Redis实现计数器(Redis支持单线程,保证了原子性)
- 分布式锁
- 延迟操作(例如电商平台下单不支付的情况下,生成token令牌,设置有效期为多少,超过了有效期,则进行订单的销毁操作)
- 分布式消息中间件
Redis环境搭建
1.创建虚拟机
安装linux环境:: 安装Linux教程
随后打开vm ware,你已经启动了一台Linux下的虚拟机
2.连接虚拟机
然后打开MobaXterm连接这台虚拟机,连接成功后:
3.安装Redis环境:
yum install -y gcc tcl
安装完毕后,将下载好的redis安装包拖拽到/usr/local/src目录下:
3.解压redis安装包
tar -zxvf redis-7.0.5.tar.gz
解压完后进入到安装包
cd redis-7.0.5/
4.启动安装包
make && make install
当你看到这三个文件,说明安装成功了
redis-cli:是redis提供的命令行客户端
redis-server:是redis的服务端启动脚本
redis-sentinel:是redis的哨兵启动脚本
Redis启动
1.前台启动Redis(在任意目录下)
redis-server
那么前台启动完成了不过你不可以做任何操作。因此我们生产环境一般都是后台启动的!
2.后台启动Redis:需要修改配置文件
1.首先进入到安装目录
cd /usr/local/src/redis-7.0.5/
2.备份配置文件
cp redis.conf redis.conf.bck
3.修改配置文件
vi redis.conf
这里我们把redis服务器密码设置成了123321,这个记住,后面要用到!
接下来就可以进行后台启动了:
4.后台启动配置文件
redis-server redis.conf
此时已经运行完配置文件,但是并没有真正的启动Redis!!想要查看是否运行成功可以使用:
ps -ef | grep redis
当看到redis-server就说明redis-server被加载了,但是还未启动!
5.杀死后台进程
使用kill命令杀死后台进程
kill -9 7668
3.Reids开机自启
1.修改配置文件
vi /etc/systemd/system/redis.service
修改为
[Unit]
Description=redis-server
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/bin/redis-server /usr/local/src/redis-7.0.5/redis.conf
PrivateTmp=true
[Install]
WantedBy=multi-user.target
2.接下来重载服务
systemctl daemon-reload
3.此时你就可以使用systemctl命令:
#启动redis
systemctl start redis
#停止redis
systemctl stop redis
#重启redis
systemctl restart redis
# 查看redis状态
systemctl status redis
#开机自启redis
systemctl enable redis
*不同动作下的Redis status:
- start :starting->started准备启动,启动完毕
- Restart stopped->starting->started 停止完毕,准备启动,启动完毕
- stop(stopping->stopped 准备停止,停止完毕)会把所有的日志全部输出
Redis客户端
1.命令行客户端
1.进入到bin目录
cd /usr/local/bin/
2.使用命令行客户端redis-cli [option] [command]
redis-cli -h 192.168.239.128 -p 6379
3.使用AUTH设置密码,与-a选项等价
#这里的密码与redis.conf文件里的requirepass 密码对应
AUTH 123321
示范:
2.桌面客户端
下载地址 RedisDesktopManager
下载好了之后,连接虚拟机的IP,密码是redis服务器的密码。(与前面设置的redis.conf文件里的requirepass 密码对应:123321)
随后就能看到16个redis的库。这些库的名称不能修改。
3.连接失败解决方案
ps:如果连不上,说明Redis服务未开启,可以使用systemctl命令启动服务:
systemctl start redis
如果还是连不上,就关闭linux下的防火墙:
systemctl stop firewalld.service
Redis的数据结构
String:将对象序列化为json字符串后存储,值是字符串。
Hash:值是哈希表,也称散列表。
List:值是list集合,与java中的LinkedList相似,是一个双向链表结构,可正向检索也可反向检索,List是有序的。
Set:Redis的Set结构与Java中的HashSet类似,可以看做是一个value为null的HashMap。因为也是一个hash表,因此具备与HashSet类似的特征。
Redis常用命令
通用命令
- KEYS:查看符合模板的所有key,不建议在生产环境设备上使用
- DEL:删除一个指定的key
- EXISTS:判断key是否存在
- EXPIRE:给一个key设置有效期,有效期到期时该key会被自动删除
- TTL:查看一个KEY的剩余有效期
TTL的值为-1时代表永久有效,-2代表过期。
String类型的命令
- SET:添加或者修改已经存在的一个String类型的键值对
- GET:根据key获取String类型的value
- MSET:批量添加多个String类型的键值对
- MGET:根据多个key获取多个String类型的value
- INCR:让一个整型的key自增1
- INCRBY:让一个整型的key自增并指定步长,例如:incrby num 2让num值自增2
- INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
- SETNX:添加一个String类型的键值对,前提是这个key不存在,否则不执行
- SETEX:添加一个String类型的键值对,并且指定有效期
Redis的Key格式
redis的key是主键且唯一的,为了区分不同类型下的同名key,redis推出了层级存储key的方式:
set ProjectName:product:1 '{"id":1,"name":"RedmiK50 Pro","price":"9999"}'
Hash
- HSET key field value:添加或者修改hash类型key的field的值
- HGET key field:获取一个hash类型key的field的值
- HGETALL:获取一个hash类型的key中的所有的field和value
- HKEYS:获取一个hash类型的key中的所有的field
- HVALS:获取一个hash类型的key中的所有的value
- HINCRBY:让一个hash类型key的字段值自增并指定步长
- HSETNX:添加一个hash类型的key的field值,前提是这个field不存在,否则不执行
List
- LPUSH key element …:向列表左侧插入一个或多个元素
- LPOP key:移除并返回列表左侧的第一个元素,没有则返回nil
- RPUSH key element …:向列表右侧插入一个或多个元素
- RPOP key:移除并返回列表右侧的第一个元素
- LRANGE key star end:返回一段角标范围内的所有元素
- BLPOP和BRPOP:与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil
Set
- SADD key member …: 向set中添加一个或多个元素
- SREM key member …:移除set中的指定元素
- SCARD key:返回set中元素的个数
- SISMEMBER key member:判断一个元素是否存在于set中
- SMEMBERS:获取set中的所有元素
- SINTER key1 key2 …:求key1与key2的交集
- SDIFF key1 key2 …:求key1与key2的差集
- SUNION key1 key2 …:求key1和key2的并集
SortedSet
Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加 hash表。
SortedSet具备下列特性:
可排序。 元素不重复查询速度快。因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。
- ZADD key score member:添加一个或多个元素到sorted set,如果已经存在则更新其score值
- ZREM key member:删除sorted set中的一个指定元素
- ZSCORE key member:获取sorted set中的指定元素的score值
- ZRANK key member:获取sorted set中的指定元素的排名ZCARD key:获取sorted set中的元素个数
- ZCOUNT key min max:统计score值在给定范围内的所有元素的个数
- ZINCRBY key increment member:让sorted set中的指定元素自增,步长为指定的increment值
- ZRANGE key min max:按照score排序后,获取指定排名范围内的元素
- ZRANGEBYSCORE key min max:按照score排序后,获取指定score范围内的元素
- ZDIFF、ZINTER、ZUNION:求差集、交集、并集
所有的排名默认都是升序,如果要降序则在命令的Z后面添加REV即可
Jedis
jedis是服务于Redis的java客户端
使用jedis需要的步骤如下:
1.引入依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.0</version>
</dependency>
2.建立连接(ip、端口号、密码认证)、释放资源
@SpringBootTest
class JedisApplicationTests {
private Jedis jedis;
@BeforeEach
void setup() {
//建立连接
jedis = new Jedis("192.168.239.128", 6379);
//设置密码
jedis.auth("123321");
jedis.select(1);
}
@AfterEach
void close(){
if (jedis!=null){
jedis.close();
}
}
}
3.测试:jedis拥有的方法与redis的命令一致
@Test
void test(){
String rs = jedis.set("name", "kxy");
System.out.println(rs);
String s = jedis.get("name");
System.out.println(s);
}
Jedis连接池
由于jedis是线程不安全的,频繁销毁和创建jedis对象会造成性能损耗,因此使用jedis连接池来代替jedis:
public class JedisConnectFactory {
private static final JedisPool jedisPool;
static {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(8);
poolConfig.setMaxIdle(8);
poolConfig.setMaxIdle(0);
jedisPool = new JedisPool(poolConfig, "192.168.239.128", 6379, 1000, "123321");
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
那么配置好了连接池,就可以从连接池中获取jedis对象了:
void setup() {
//建立连接
jedis = JedisConnectFactory.getJedis();
//设置密码
jedis.auth("123321");
jedis.select(1);
}
SpringDataRedis
RedisTemplate
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:
使用springboot内置的SpringDataRedis
1. 导入springboot内置redis依赖和连接池
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
2. 配置文件
spring:
redis:
host: 192.168.239.128
port: 6379
password: 123321
lettuce:
pool:
max-active: 8 # 最大连接
max-idle: 8 # 最大空闲连接
min-idle: 0 #
max-wait: 100 # 等待连接时间
3.测试
@SpringBootTest
class RedisApplicationTests {
@Resource
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
redisTemplate.opsForValue().set("name","lisi");
Object name = redisTemplate.opsForValue().get("name");
System.out.println(name);
}
}
由于RedisTemplate 默认的序列化方式是jdk 序列化,这样就会导致我们存储key或value的最终显示在客户端上会出现地址,这是我们不期望的。
因此我们需要写一个配置类去修改redisTemplate的序列化方式:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
//创建RedisTemplate对象
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 创建JSON序列化工具
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
// 设置Key的序列化
redisTemplate.setKeySerializer(serializer);
redisTemplate.setHashKeySerializer(serializer);
// 设置Value的序列化
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashValueSerializer(serializer);
//返回
return redisTemplate;
}
}
通用版:
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
// Hash的key也采用StringRedisSerializer的序列化方式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
}
StringRedisTemplate
由于Json的序列化方式,在反序列化的的前提是确定class类型,因此会把class字节码对象存入到Json对象中,而class字节码对象会带来额外的内存开销。
为了解决这个问题,我们通常不会用json的序列化器,而是使用String序列化器:只能存储String类型的key和value。当存储的是一个java对象时,则需要程序员手动的完成对象的序列化和反序列化。
而正好spring提供了一个StringRedisTemplate类,它的序列化方式默认就是String方式。
以下是分别是存储普通的字符串的key和value以及一个java对象序列化成json对象存储到redis的示例
@SpringBootTest
class RedisStringTests {
@Autowired
private StringRedisTemplate redisTemplate;
@Test
void testString() {
//写入数据存入redis
redisTemplate.opsForValue().set("name1","zs1");
//取数据
Object name1 = redisTemplate.opsForValue().get("name1");
System.out.println(name1);
}
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testSaveUser() throws JsonProcessingException {
User user = new User("zhangsan", 21);
//手动序列化:将java对象转成json字符串
String json = mapper.writeValueAsString(user);
//数据存入redis
redisTemplate.opsForValue().set("user:200",json);
//获取数据
String jsonUser = redisTemplate.opsForValue().get("user:200");
//手动反序列化:
User user1 = mapper.readValue(jsonUser, User.class);//参数1:要反序列化的json对象。参数2:要反序列化成的类型
System.out.println("user1="+user1);
}
}
总结:redisTemplate的序列化两种方式
- 在RedisConfig配置类自定义redisTemplate方法,在此方法内修改RedisTemplate的默认序列化器为只保存String类型的key,value的序列化器,比如jackson2序列化器,fastJson序列化器等等。
- 使用spring提供的StringRedisTemplate,写入redis的时候手动的把java对象序列化为json对象,读取redis的数据时手动的把json对象反序列化为Java对象。