Redis:REmote DIctionary Server(远程字典服务器)
是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(Key/Value)分布式内存数据库,基于内存运行,并支持持久化的NoSQL数据库,是当前最热门的NoSQL数据库之一,也被人们称为数据结构服务器。
Redis与其他key-value缓存产品有以下三个特点
redis默认16个数据库,类似数组下标从零开始,初始默认使用零号库。
在redis的配置文件redis.conf中,可以查看数据库的默认配置!!!
Select命令切换数据库
select 7 #切换到第七个数据库
Dbsize查看当前数据库的key的数量
DBSIZE
Flushdb:清空当前库
Flushall:清空全部的库
关于Key的一些操作
# 查看所有的key
keys *
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set name haha
OK
127.0.0.1:6379> keys *
1) "name"
# exists key 的名字,判断某个key是否存在
127.0.0.1:6379> EXISTS name
(integer) 1
127.0.0.1:6379> EXISTS name1
(integer) 0
# 移除当前库中的key
move key db ---> 当前库就没有了,被移除了
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> keys *
(empty list or set)
# 为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。
expire key 秒钟:
# ttl key 查看还有多少秒过期,-1 表示永不过期,-2 表示已过期
127.0.0.1:6379> set name haha
OK
常用命令说明:
127.0.0.1:6379> EXPIRE name 10
(integer) 1
127.0.0.1:6379> ttl name
(integer) 4
127.0.0.1:6379> ttl name
(integer) 3
127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> ttl name
(integer) 1
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> keys *
(empty list or set)
# 查看你的key是什么类型
type key
127.0.0.1:6379> set name haha
OK
127.0.0.1:6379> get name
"haha"
127.0.0.1:6379> type name
string
更多redis命令
为什么redis是单线程
redis 6 之前的版本是单进程、单线程的,6版本之后支持多线程!!!
redis很快,是因为redis是基于内存的操作,CPU不是redis的瓶颈,redis
的瓶颈最有可能是机器内存的大小或者网络带宽!!!
先说两个误区:一、高性能的服务器不一定都是多进程、多线程的;二、多线程不一定都不比单线程快,比如单核机器。
在我们通常的认知中,高性能都是通过多进程、多线程实现的。比如Nginx是多进程单线程的,Memcached是单进程多线程的。
在计算机的世界中,CPU的速度是远大于内存的速度的,同时内存的速度也是远大于硬盘的速度。redis的操作都是基于内存的,绝大部分请求是纯粹的内存操作,非常迅速,使用单线程可以省去多线程时CPU上下文会切换的时间,也不用去考虑各种锁的问题,不存在加锁释放锁操作,没有死锁问题导致的性能消耗。对于内存系统来说,多次读写都是在一个CPU上,没有上下文切换效率就是最高的!既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章的采用单线程的方案了(毕竟采用多线程会有很多麻烦)。
redis的用处
五种数据结构
本篇笔记仅对redis的基本操作进行总结,关于底层的实现,详见后续学习笔记!!!
单值单value
常用操作、增删查
127.0.0.1:6379> set hello redis
OK
127.0.0.1:6379> get hello
"redis"
127.0.0.1:6379> del hello
(integer) 1
127.0.0.1:6379> get hello
(nil)
append、strlen
# hello不存在
127.0.0.1:6379> exists hello
(integer) 0
# # 对不存在的key进行APPEND,等同于 SET 语句
127.0.0.1:6379> append hello redis2
(integer) 6
127.0.0.1:6379> get hello
"redis2"
# 对已存在的key进行APPEND,直接在string后加内容
127.0.0.1:6379> append hello redis3
(integer) 12
127.0.0.1:6379> get hello
"redis2redis3"
127.0.0.1:6379> strlen hello
(integer) 12
incr、decr 加1、减1
incrby、decrby 加上、减去指定的增量值
String类型的value还可以存储数字
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> decr views
(integer) 1
127.0.0.1:6379> get views
"1"
lpush、rpush 添加list数据
#lpush:将一个或多个值插入到列表头部。(左)
#rpush:将一个或多个值插入到列表尾部。(右)
lpush list-key item
rpush list-key item
lrange、lindex 获取数据
#lrange:返回列表中指定区间内的元素,区间以偏移量START和STOP指定
lrange list-key start stop
#lindex:返回index位置的元素
lindex list-key
lpop、rpop 删除list中的数据
#lpop 命令用于移除并返回列表的第一个元素。当列表 key 不存在时,返回nil 。
lpop list-key
#rpop 移除列表的最后一个元素,返回值为移除的元素。
rpop list-key
应用场景:
Redis list的应用场景非常多,也是Redis最重要的数据结构之一。我们可以轻松地实现最新消息排行等功能。Lists的另一个应用就是消息队列,可以利用Lists的PUSH操作,将任务存在Lists中,然后工作线程再用POP操作将任务取出进行执行。
单值多value
sadd 添加元素
# sadd 将一个或多个成员元素加入到集合中,不能重复
127.0.0.1:6379> sadd set a,b
(integer) 1
127.0.0.1:6379> sadd set c
(integer) 1
127.0.0.1:6379> sadd set d,eee,ff
(integer) 1
smembers 获取数据
# smembers 返回集合中的所有的成员。
127.0.0.1:6379> smembers set
1) "d,eee,ff"
2) "a,b"
3) "c"
sismember 判断成员元素是否是集合的成员。
127.0.0.1:6379> smembers set
1) "d,eee,ff"
2) "a,b"
3) "c"
127.0.0.1:6379> sismember set c
(integer) 1
127.0.0.1:6379> sismember set a
(integer) 0
应用场景:
Redis为集合提供了求交集、并集、差集等操作,故可以用来求共同好友等操作。
zadd 添加数据
# 将一个或多个成员元素及其分数值加入到有序集当中。
127.0.0.1:6379> zadd zset 3 haha
(integer) 1
127.0.0.1:6379> zadd zset 1 ming 2 hong
(integer) 2
zrange 获取数据
# 返回有序集中,指定区间内的成员
127.0.0.1:6379> zrange zset 0 1
1) "ming"
2) "hong"
127.0.0.1:6379> zrange zset 0 -1
1) "ming"
2) "hong"
3) "haha"
zrangebyscore 返回分数score之间的数据
# 返回有序集合中指定分数区间的成员列表。有序集成员按分数值递增(从小到大)
次序排列。
127.0.0.1:6379> zrangebyscore zset 0 1
1) "ming"
127.0.0.1:6379> zrangebyscore zset 1 3
1) "ming"
2) "hong"
3) "haha"
zrem 删除数据
# 移除有序集中的一个或多个成员
127.0.0.1:6379> zrem zset hong
(integer) 1
应用场景:
以某个条件为权重,比如按顶的次数排序,ZREVRANGE命令可以用来按照得分来获取前100名的用户,ZRANK可以用来获取用户排名,非常直接而且操作容易。Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。
kv模式不变,但V是一个键值对
hset 添加元素
# hset key field value
127.0.0.1:6379> hset hash hash1 value1
(integer) 1
127.0.0.1:6379> hset hash hash1 value2
(integer) 0
127.0.0.1:6379> hset hash hash2 value2 hash3 value3
(integer) 2
hget 、hgetall 获取元素
# hget key field
127.0.0.1:6379> hget hash hash1
"value1"
# hgetall key
127.0.0.1:6379> hgetall hash
1) "hash1"
2) "value2"
3) "hash2"
4) "value2"
5) "hash3"
6) "value3"
hmset、hmget 对多个field-value对进行操作
# 同时将多个field-value对设置到哈希表中。会覆盖哈希表中已存在的字段。
127.0.0.1:6379> hmset mhash hash1 value1 hash2 value2
OK
127.0.0.1:6379> hmget mhash hash1 hash2
1) "value1"
2) "value2"
hdel 删除数据
# 用于删除哈希表key中的一个或多个指定字段
127.0.0.1:6379> hdel hash hash1 hash2
(integer) 2
127.0.0.1:6379> hgetall hash
1) "hash3"
2) "value3"
应用场景:
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。存储部分变更的数据,如用户信息等。
配置文件开头就说了redis-server的使用
Redis启动的时候,通过配置文件来启动
命令:redis-server /usr/local/bin/myredis/redis.conf(配置文件的路径)
单位 Units
includes 可以包含其他配置文件
network
bind 127.0.0.1 # 绑定的ip
protected-mode yes # 保护模式,是否受保护,默认开启
port 6379 # 默认端口
general 通用配置
# 默认情况下,Redis不作为守护进程运行。需要开启的话,改为 yes
daemonize yes
# 可通过upstart和systemd管理Redis守护进程
supervised no
# 以后台进程方式运行redis,则需要指定pid 文件
pidfile /var/run/redis_6379.pid
# 日志级别。可选项有:
# debug(记录大量日志信息,适用于开发、测试阶段);
# verbose(较多日志信息);
# notice(适量日志信息,使用于生产环境);
# warning(仅有部分重要、关键信息才会被记录)。
loglevel notice
# 日志文件的位置,当指定为空字符串时,为标准输出
logfile ""
# 设置数据库的数目。默认的数据库是DB 0
databases 16
# 是否总是显示logo,开启redis服务那个logo
always-show-logo yes
快照
什么是快照呢?快照是实现持久化的一种方法。快照,可以理解为拍照一样,把整个内存数据映射到硬盘中,保存一份到硬盘,因此恢复数据起来比较快,把数据映射回去即可!!!
# 900秒(15分钟)内至少1个key值改变(则进行数据库保存--持久化)
save 900 1
# 300秒(5分钟)内至少10个key值改变(则进行数据库保存--持久化)
save 300 10
# 60秒(1分钟)内至少10000个key值改变(则进行数据库保存--持久化)
save 60 10000
stop-writes-on-bgsave-error yes # 持久化出现错误后,是否依然进行继续进行工作
rdbcompression yes # 使用压缩rdb文件 yes:压缩,但是需要一些cpu的消耗。no:不压
缩,需要更多的磁盘空间
rdbchecksum yes # 是否校验rdb文件,更有利于文件的容错性,但是在保存rdb文件的时候,会有大概10%的性能损耗
dbfilename dump.rdb # dbfilenamerdb文件名称
dir ./ # dir 数据目录,数据库的写入会在这个目录。rdb、aof文件也会写在这个目录
注:rdb文件是持久化的文件(快照文件),它保存了redis 在某个时间点上的数据集。 这种文件非常适合用于进行备份和灾难恢复。
security 安全
访问密码的查看,设置和取消
# 启动redis
# 连接客户端
# 获得和设置密码
config get requirepass
config set requirepass "123456"
#测试ping,发现需要验证
127.0.0.1:6379> ping
NOAUTH Authentication required.
# 验证
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> ping
PONG
客户端的一些限制
maxclients 10000 # 设置能连上redis的最大客户端连接数量
maxmemory # redis配置的最大内存容量
maxmemory-policy noeviction # maxmemory-policy 内存达到上限的处理策略
6种处理策略
appendonly 模式
默认使用rdb持久化方式,不开启aof模式
appendonly no # 是否以append only模式作为持久化方式
appendfilename "appendonly.aof" # appendfilename AOF 文件名称
appendfsync everysec # appendfsync aof持久化策略的配置
AOF持久化配置策略
redis单条命令是保证原子性的,但是事务不保证原子性!!!
Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
Redis事务没有隔离级别的概念:
批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行!
Redis不保证原子性:
Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。
Redis事务的三个阶段:
Redis事务相关命令如下:
watch key1 key2 ... #监视一个或多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断 ( 类似乐观锁 )
multi # 标记一个事务块的开始( queued )
exec # 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 )
discard # 取消事务,放弃事务块中的所有命令
unwatch # 取消watch对所有key的监控
Watch命令详解:
watch监控指令类似于乐观锁,在事务提交时,如果watch监控的多个KEY中任何KEY的值已经被其他客户端更改,则使用EXEC执行事务时,事务队列将不会被执行,同时返回Nullmulti-bulk应答以通知调用者事务执行失败。
测试watch命令的使用!!!
转账,A转给B100元,A有1000,B有0
正常执行成功!
127.0.0.1:6379> set A 1000
OK
127.0.0.1:6379> set B 0
OK
127.0.0.1:6379> watch A
OK
#事务正常结束,数据期间没有发生变动,这个时候就正常执行成功!!!
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby A 100
QUEUED
127.0.0.1:6379> incrby B 100
QUEUED
127.0.0.1:6379> exec
1) (integer) 900
2) (integer) 100
场景:小明去给账户充钱(A),充到1000;小红用账户的钱(A)给小李转账(B)100;俩人同时进行!!!
127.0.0.1:6379> get A
"900"
127.0.0.1:6379> set A 1000
OK
127.0.0.1:6379> watch A # 加锁
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby A 100
QUEUED
127.0.0.1:6379> incrby B 100
QUEUED
127.0.0.1:6379> exec
(nil)
在小红转账期间,加上watch乐观锁,小明给账户充钱了,小红转账失败!!!
注:一但执行 EXEC 开启事务的执行后,无论事务使用执行成功, WARCH 对变量的监控都将被取消。
故当事务执行失败后,需重新执行WATCH命令对变量进行监控,并开启新的事务进行操作。
Jedis是Redis官方推荐的Java连接开发工具!!!
API与Linux的redis命令一致,不重复了。
在SpringBoot2.x之后,jedis被替换为了lettuce
jedis:采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全,使用jedis pool连接池!更像BIO模式!!!
lettuce:采用netty,实例可以再多个线程种进行共享,不存在线程不安全的情况,可以减少线程数据,更像NIO模式!!!
在SpringBoot中一般使用RedisTemplate提供的方法来操作Redis。
导入pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置文件properties或者yaml
spring:
redis:
host: 127.0.0.1
port: 6379
password: 123456
lettuce:
shutdown-timeout: 0ms
使用RedisTemplate来操作
@SpringBootTest
class SpringdataRedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
//操作String类型
redisTemplate.opsForValue().set("hello","redis");
System.out.println(redisTemplate.opsForValue().get("hello"));
}
}
当然,RedisTemplate也可以根据需求自己封装,命名为RedisTemplate即可!!!