目录
概念:
Redis优势:
Redis数据类型注意事项:
Redis与数据库注意事项:
Redis基本操作
Redis不同数据类型详解及操作
String类型:
Hash哈希表
基本操作:
List列表
List基本操作:
集合Set
Set基本操作:
有序集合sorted set
有序集合sorted set基本操作
HyperLogLog
基本操作:
发布订阅:
发布订阅原理
实例演示:
订阅发布使用场景
订阅发布其他基本操作
模式匹配订阅
插入消息:
取消该订阅:
Redis事务:
定义
实例
事务其余操作:
Redis为什么不支持回滚
Redis脚本
定义
执行脚本命令:
参数说明:
脚本示例:
执行脚本语句:
脚本其余命令:
Redis连接:(连接数据库)
基本命令:
IDEA中Redis连接数据库:
Redis 数据备份与恢复
基本命令:
Redis客户端连接
最大连接数设置:
客户端基本命令:
Redis管道技术:
使用管道技术原因
适用场景:
缺点:
实例:
概念:
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
简单来说就是:使用键值对的存储方式周期性的将更新的数据写入磁盘,或者把修改操作写入追加的记录文件。
Redis优势:
- 数据间没有必然的关联关系,内部存储为键值对形式
- 操作具有原子性,采用单线程进行工作,不用考虑并发影响。
- 存取速度快,适用于高读量,高并发。
- 支持key-value中的value具有丰富数据类型:字符串String、列表list、集合set、散列hash、有序集合sorted_set、基数hyperlog.
另外,Redis 除了做缓存之外,也经常用来做分布式锁,甚至是消息队列。Redis 提供了多种数据类型来支持不同的业务场景。Redis 还支持事务 、持久化、Lua 脚本、多种集群方案。
另外,Redis 除了做缓存之外,也经常用来做分布式锁,甚至是消息队列。Redis 提供了多种数据类型来支持不同的业务场景。Redis 还支持事务 、持久化、Lua 脚本、多种集群方案。
Redis数据类型注意事项:
- Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念。
- Redis是一个字典结构的存储服务器,而实际上一个Redis实例提供了多个用来存储数据的字典,客户端可以指定将数据存储在哪个字典中。
- Redis默认支持16个数据库,每个数据库对外都是一个从0开始的递增数字命名,可以通过配置databases来修改这一数字。客户端与Redis建立连接后会自动选择0号数据库,不过可以随时使用SELECT命令更换数据库,如要选择1号数据库:
127.0.0.1:6379> select 0
OK
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get key
(nil)
127.0.0.1:6379> select 0
OK
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get key
(nil)
我还没创建数据库1,所显示为空
Redis与数据库注意事项:
- Redis不支持为每个数据库设置不同的访问密码。数据库访问密码只能相同。
- 多个数据库之间并不是完全隔离的,比如FLUSHALL命令可以清空一个Redis实例中所有数据库中的数据。
Redis基本操作
1、set key value//存入键值对
set name xixi
2、get key//获取键值对
get name
3、clear //清屏
4、help//命令
5、quit/exit//退出
Redis不同数据类型详解及操作
String类型:
1、SET key value
设置指定 key 的值。
redis 127.0.0.1:6379> SET key "value"
OK
2、get key
获取指定 key 的值。返回 key 的值,如果 key 不存在时,返回 nil。 如果 key 不是字符串类型,那
么返回一个错误。
redis> GET db
"redis"
3、getrange key start end
返回 key 中字符串值的子字符
redis 127.0.0.1:6379> SET mykey "This is my test key"
OK
redis 127.0.0.1:6379> GETRANGE mykey 0 3
"This"
redis 127.0.0.1:6379> GETRANGE mykey 0 -1
"This is my test key"
4、getset key value
将给定 key 的值设为 value ,并返回 key 的旧值(old value)。 当 key 没有旧值时,即 key 不存在时,返回 nil 。当 key 存在但不是字符串类型时,返回一个错误。、
redis> GETSET db redis # redis是新值,返回旧值 mongodb
"mongodb"
5、MGET key1 key2..
批量获取所有给定 key 的值。
redis 127.0.0.1:6379> SET key1 "hello"
OK
redis 127.0.0.1:6379> SET key2 "world"
OK
redis 127.0.0.1:6379> MGET key1 key2 someOtherKey
1) "Hello"
2) "World"
3) (nil)
6、MSET key value key value ...
批量设置多个 key-value 对。
redis 127.0.0.1:6379> MSET key1 "Hello" key2 "World"
OK
8、SETEX key seconds value
设值并将 key 的生命周期设为 seconds (以秒为单位)。
redis 127.0.0.1:6379> SETEX mykey 60 redis
OK
redis 127.0.0.1:6379> TTL mykey #查询生命周期
60
redis 127.0.0.1:6379> GET mykey
"redis"
9、SETNX key value
只有在 key 不存在时设置 key 的值。
redis> EXISTS job # job 不存在
(integer) 0
redis> SETNX job "programmer" # job 设置成功返回1,失败返回0
(integer) 1
redis> SETNX job "code-farmer" # 尝试覆盖 job ,失败
(integer) 0
redis> GET job # 没有被覆盖
"programmer"
10、APPEND key value
APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾。并返回追加后字串长度
redis> APPEND myphone "nokia" # 对不存在的 key 进行 APPEND ,等同于 SET myphone "nokia"
(integer) 5 # 字符长度
# 对已存在的字符串进行 APPEND
redis> APPEND myphone " - 1110" # 长度从 5 个字符增加到 12 个字符
(integer) 12
11、INCR key
将 key 中储存的数字值增一。
redis> SET page_view 20#这里是设置数字值以字符穿形式保留
OK
redis> INCR page_view
(integer) 21
Hash哈希表
由于对象类的数据存储更行操作繁琐,所以需要对存储数据进行编组,一个存储空间保存多个键值对数据,因此使用string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。
基本操作:
1、 HSET key field value
将哈希表 key 中的字段 field 的值设为 value 。
2、HGET key field
获取存储在哈希表中指定字段的值。
HSET myhash field1 "foo"
OK
redis 127.0.0.1:6379> HGET myhash field1
"foo"
3、 HGETALL key
获取在哈希表中指定 key 的所有字段和值
redis> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "World"
4、HDEL key field1 [field2]
删除一个或多个哈希表字段
redis 127.0.0.1:6379> HDEL myhash field1 #删除成功返回1
(integer) 1
redis 127.0.0.1:6379> HDEL myhash field2 #删除失败返回0
(integer) 0
5、HEXISTS key field
查看哈希表 key 中,指定的字段是否存在。
redis 127.0.0.1:6379> HEXISTS myhash field1#含有返回1
(integer) 1
redis 127.0.0.1:6379> HEXISTS myhash field2#不含返回0
(integer) 0
6、HMSET key field1 value1 field2 value2
同时将多个 field-value (域-值)对设置到哈希表 key 中。
redis 127.0.0.1:6379> HMSET myhash field1 "Hello" field2 "World"
OK
7、HMGET key field1 [field2]
获取所有给定字段的值
redis 127.0.0.1:6379> HMGET myhash field1 field2 nofield
1) "foo"
2) "bar"
3) (nil)
8、 HLEN key
获取哈希表中字段的数量
redis 127.0.0.1:6379> HLEN myhash #不存在时返回0
(integer) 2
9、HKEYS key
获取所有哈希表中的字段
redis 127.0.0.1:6379> HSET myhash field1 "foo"
(integer) 1
redis 127.0.0.1:6379> HSET myhash field2 "bar"
(integer) 1#返回包含哈希表中所有域(field)列表。 当 key 不存在时,返回一个空列表。
redis 127.0.0.1:6379> HKEYS myhash
1) "field1"
2) "field2"
注意:
- hash类型下的的value只能存字符串,不允许存其他类型
- 每个hash最大可存232 - 1 键值对
List列表
存储需求:一个存储空间保存多个数据,并通过数据可体现进入顺序,底层使用双向链表存储结构。
注意:
- list具有索引概念,数据以队列或栈形式进行出队入队、出栈入栈操作,
- List中保存的是String类型,总容量有限,最大可存232 – 1元素
List基本操作:
1、LPUSH key value1 [value2]
与 RPUSH key value1 [value2]
将一个或多个值插入到列表头部
127.0.0.1:6379> LPUSH list1 "foo" #返回值为列表长度
(integer) 1
127.0.0.1:6379> LPUSH list1 "bar"
(integer) 2
127.0.0.1:6379> LRANGE list1 0 -1 #查询列表值
1) "bar"
2) "foo"
redis 127.0.0.1:6379> RPUSH mylist "hello" #执行 RPUSH 操作后,列表的长度。
(integer) 1
redis 127.0.0.1:6379> RPUSH mylist "foo"
(integer) 2
redis 127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "foo"
2、LPOP key
移出并获取列表的第一个元素
RPOP key
移除列表的最后一个元素,返回值为移除的元素。
redis 127.0.0.1:6379> RPUSH list1 "foo"
(integer) 1
redis 127.0.0.1:6379> RPUSH list1 "bar"
(integer) 2
redis 127.0.0.1:6379> LPOP list1 #移除尾元素
"foo"
redis> RPUSH mylist "one" #RPUSH插入元素
(integer) 1
redis> RPUSH mylist "two"
(integer) 2
redis> RPUSH mylist "three"
(integer) 3
redis> RPOP mylist #RPOP移除尾元素
"three"
redis> LRANGE mylist 0 -1
1) "one"
2) "two"
3、LRANGE key start stop
获取列表指定范围内的元素
4、LINDEX key index
通过索引获取列表中的元素
redis 127.0.0.1:6379> LINDEX mylist -1 #下标为指定索引值的元素。
"World"
redis 127.0.0.1:6379> LINDEX mylist 3 # index不在 mylist 的区间范围内
(nil)
5、 LLEN key
获取列表长度
redis 127.0.0.1:6379> LLEN list1
(integer) 2 #返回列表长度
6、LREM key count value
移除指定元素
redis> LREM mylist -2 "hello" #删除指定元素
(integer) 2
#count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相同的元素,数量为 COUNT 。
#count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相同的元素,数量为 COUNT 的绝对值。
#count = 0 : 移除表中所有与 VALUE 相等的值。
集合Set
- Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。如果重复,只保留一份。
- Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1),与哈希表不同的是,它仅存储键,不存储值。
Set基本操作:
1、SADD key member1 [member2]
向集合添加一个或多个成员
2、SMEMBERS key
返回集合中的所有成员
redis 127.0.0.1:6379> SADD myset "hello"#插入成功返回1
(integer) 1
redis 127.0.0.1:6379> SADD myset "foo"
(integer) 1
redis 127.0.0.1:6379> SADD myset "hello"#插入失败返回0
(integer) 0
redis 127.0.0.1:6379> SMEMBERS myset#查询集合数据
1) "hello"
2) "foo"
3、SREM key member1 [member2]
删除集合成员
redis 127.0.0.1:6379> SREM myset1 "hello"#删除成功返回1
(integer) 1
redis 127.0.0.1:6379> SREM myset1 "foo"#该成员不存在,删除失败返回0
(integer) 0
4、SCARD key
获取集合的成员总量
redis 127.0.0.1:6379> SCARD myset#返回集合成员数量,当集合key不存在时返回0
(integer) 2
5、SISMEMBER key member
判断 member 元素是否是集合 key 的成员
redis 127.0.0.1:6379> SISMEMBER myset1 "hello"#是则返回1
(integer) 1
redis 127.0.0.1:6379> SISMEMBER myset1 "world"#不是返回0
(integer) 0
6、SRANDMEMBER key [count]
随机获取集合中指定数据
redis 127.0.0.1:6379> SRANDMEMBER myset1 #只查询集合,则返回一个元素
"bar"
redis 127.0.0.1:6379> SRANDMEMBER myset1 2 #如果提供了 count 参数,那么返回一个数组;
1) "Hello"
2) "world"
7、SPOP key
随机找一个元素删除
redis> SPOP myset
"one"
redis> SPOP myset 3 #随机找三个元素删除
1) "five"
2) "four"
3) "two"
8、求两个集合的交、并、差集
SINTER key1 [key2]
SUNIOn key1 [key2]
SDIFF key1 [key2]
redis 127.0.0.1:6379> SADD myset "hello"
(integer) 1
redis 127.0.0.1:6379> SADD myset "foo"
(integer) 1
redis 127.0.0.1:6379> SADD myset "bar"
(integer) 1
redis 127.0.0.1:6379> SADD myset2 "hello"
(integer) 1
redis 127.0.0.1:6379> SADD myset2 "world"
(integer) 1
redis 127.0.0.1:6379> SINTER myset myset2#求交集,返回交集列表
1) "hello"
redis> SUNIOn myset myset2 #求并集
1) " hello "
2) " foo "
3) " bar "
4) " world "
redis> SDIFF myset myset2 #求补集
1) " foo "
2) " bar "
3) " world "
#求两个集合的交集并放到指定的集合中(myset)成功返回1
redis 127.0.0.1:6379> SINTERSTORE myset myset1 myset2
(integer) 1
#将给定集合的并集存储在指定的集合 destination 中结果集中的元素数量。
redis> SUNIOnSTORE myset myset1 myset2
(integer) 4
#将给定集合之间的差集存储在指定的集合中。如果指定的集合 key 已存在,则会被覆盖。
redis 127.0.0.1:6379> SDIFFSTORE myset myset1 myset2
(integer) 3
有序集合sorted set
- 有序集合是String元素集合,不允许重复
- 每个元素由一个double类型分数标序,由小到大,分数可以重复,元素不允许重复、
有序集合sorted set基本操作
1、ZADD key score1 member1 [score2 member2]
添加成员数据,或者更新已存在成员的分数
redis> ZADD myzset 1 "one" #插入序号为1的成员
(integer) 1
redis> ZADD myzset 1 "uno" #序号可重复
(integer) 1
redis> ZADD myzset 2 "two" 3 "three" #插入多个数据
(integer) 2
2、 ZRANGE key start stop [WITHSCORES]
通过索引区间返回有序集合指定区间内的成员
ZREVRANGE key start stop [WITHSCORES]
返回有序集中指定区间内的成员,通过索引,分数从高到低
redis> ZRANGE myzset 0 -1 WITHSCORES #根据分数查询集合,返回成员和分数
1) "one"
2) "1"
3) "uno"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"
redis> ZREVRANGE myzset 0 -1 WITHSCORES #根据分数查询集合,返回成员和分数
1) "three"
2) "3"
3) "two"
4) "2"
5) "uno"
6) "1"
7) "one"
8) "1"
3、ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT]
通过分数返回有序集合指定区间内的成员
redis 127.0.0.1:6379> ZADD salary 2500 jack # 测试数据
(integer) 0
redis 127.0.0.1:6379> ZADD salary 5000 tom
(integer) 0
redis 127.0.0.1:6379> ZADD salary 12000 peter
(integer) 0redis 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf # 显示整个有序集
1) "jack"
2) "tom"
3) "peter"
redis 127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf WITHSCORES # 显示整个有序集及成员的 score 值
1) "jack"
2) "2500"
3) "tom"
4) "5000"
5) "peter"
6) "12000"
redis 127.0.0.1:6379> ZRANGEBYSCORE salary -inf 5000 WITHSCORES # 显示工资 <=5000 的所有成员
1) "jack"
2) "2500"
3) "tom"
4) "5000"
redis 127.0.0.1:6379> ZRANGEBYSCORE salary (5000 400000 # 显示工资大于 5000 小于等于 400000 的成员
1) "peter"
4、ZREVRANGEBYSCORE key max min [WITHSCORES]
返回有序集中指定分数区间内的成员,分数从高到低排序
redis 127.0.0.1:6379> ZADD salary 10086 jack
(integer) 1
redis > ZADD salary 5000 tom
(integer) 1
redis 127.0.0.1:6379> ZADD salary 7500 peter
(integer) 1
redis 127.0.0.1:6379> ZADD salary 3500 joe
(integer) 1
redis 127.0.0.1:6379> ZREVRANGEBYSCORE salary +inf -inf # 逆序排列所有成员
1) "jack"
2) "peter"
3) "tom"
4) "joe"
redis 127.0.0.1:6379> ZREVRANGEBYSCORE salary 10000 2000 # 逆序排列薪水介于 10000 和 2000 之间的成员
1) "peter"
2) "tom"
3) "joe"
5、按条件删除数据
ZREMRANGEBYSCORE key min max
移除有序集合中给定的字典区间的所有成员
# 移除所有薪水在 1500 到 3500 内的员工
redis 127.0.0.1:6379> ZREMRANGEBYSCORE salary 1500 3500
(integer) 2
6、ZCARD key
获取有序集合的成员数
redis> ZADD myzset 1 "one"
(integer) 1
redis> ZADD myzset 2 "two"
(integer) 1
redis> ZCARD myzset #当key不存在时,返回0,返回有序集合的成员数,
(integer) 2
HyperLogLog
Redis 在 2.8.9 版本添加了 HyperLogLog 数据结构。
- 他是用来做基数统计算法的,输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
- 因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
基数:是指数据集中不重复元素的数量
基本操作:
1、PFADD key element [element ...]
添加指定元素到 HyperLogLog 中。
2、PFCOUNT key [key ...]
返回给定 HyperLogLog 的基数估算值。
redis 127.0.0.1:6379> PFADD mykey a b c d e f g h i j
(integer) 1
redis 127.0.0.1:6379> PFCOUNT mykey
(integer) 10
3、 PFMERGE destkey sourcekey [sourcekey ...]
将多个 HyperLogLog 合并为一个 HyperLogLog
redis> PFADD hll1 foo bar zap a #添加元素进基数,执行成功返回1
(integer) 1
redis> PFADD hll2 a b c foo
(integer) 1
redis> PFMERGE hll3 hll1 hll2#将hll1 hll2加起来放进hll3
"OK"
redis> PFCOUNT hll3
(integer) 6
发布订阅:
Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。
消息发布者,即publish客户端,无需独占链接,你可以在publish消息的同时,使用同一个redis-client链接进行其他操作(例如:INCR等)
消息订阅者,即subscribe客户端,需要独占链接,即进行subscribe期间,redis-client无法穿插其他操作,此时client以阻塞的方式等待“publish端”的消息;这一点很好理解,因此subscribe端需要使用单独的链接,甚至需要在额外的线程中使用。
发布订阅原理
Redis 客户端可以订阅任意数量的频道。
下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
实例演示:
发布-订阅需要打开两个redis-cli客户端,首先先创建订阅频道
# SUBSCRIBEchannel1…订阅给定的一个或多个频道的信息。
redis 127.0.0.1:6379> SUBSCRIBE mychannel
Reading messages... (press Ctrl-C to quit)
1) "subscribe" #显示模式,subscribe是订阅
2) "mychannel" #显示订阅的频道
3) (integer) 1 #订阅成功返回1
1) "message"
2) "mychannel"
3) "a"
第二个redis-cli客户端,在同一个频道 mychannel发布消息
PUBLISH channel message
将信息发送到指定的频道。
redis 127.0.0.1:6379> PUBLISH mychannel "send the message to mtchannel"
(integer) 1 #发送消息成功返回1
此时第一个客户端,也就是订阅者客户端会显示发送的消息
# SUBSCRIBEchannel1…订阅给定的一个或多个频道的信息。
redis 127.0.0.1:6379> SUBSCRIBE mychannel
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "mychannel"
3) (integer) 1
1) "message"#显示模式,此处是消息
2) "mychannel"#显示订阅者频道
3) "send the message to mtchannel "#显示消息内容
订阅发布使用场景
该模式主要用于用户编辑某个模块需要清除缓存,需要在编辑完某模块后发布到频道,在订阅该频道实现该模块清除缓存。
订阅发布其他基本操作
1、PUBSUB subcommand [argument [argument ...]]
查看订阅与发布系统状态
redis 127.0.0.1:6379> PUBSUB CHANNELS
(empty list or set)#若此时有值,则返回活跃频道的列表
2、 UNSUBSCRIBE [channel [channel ...]]
指退订给定的频道。
redis 127.0.0.1:6379> UNSUBSCRIBE mychannel
1) "unsubscribe"
2) " send the message to mtchannel "
3) (integer) 0
模式匹配订阅
Redis 的Pub/Sub实现支持模式匹配。
如果需要订阅test.name test.addr test.age等test频道,可以直接订阅全风格的模式如:
PSUBCSCRIBE test.*
插入消息:
127.0.0.1:6379> PUBLISH test.name haha
(integer) 1
取消该订阅:
PUNSUBSCRIBE test.*
127.0.0.1:6379> PUBLISH test.name haha
(integer) 1
PUNSUBSCRIBE test.*
Redis事务:
定义
事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,MULTI、EXEC、
DISCARD和WATCH命令是Redis事务功能的基础。
- redis的事务中,一次执行多条命令,本质是一组命令的集合,一个事务中所有的命令将被序列化,即按顺序执行而不会被其他命令插入
- 批量操作在发送 EXEC (执行)命令前被放入队列缓存。
- 事务中,EXEC (执行)命令后,一个操作失败不影响剩下命令执行。
- 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
实例
一个事务从开始到执行会经历以下三个阶段:
开始事务--命令入队--执行事务。
redis 127.0.0.1:6379> MULTI #标记一个事务块的开始。
OK
#将set命令放进队列中
redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED
#将get命令放进队列中
redis 127.0.0.1:6379> GET book-name
QUEUED
#将添加String命令放进队列中
redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED
#将查询tag命令放进队列中
redis 127.0.0.1:6379> SMEMBERS tag
QUEUED
redis 127.0.0.1:6379> EXEC#执行所有事务块内的命令。
1) OK #执行SET book-name "Mastering C++ in 21 days"
2) "Mastering C++ in 21 days" #执行GET book-name
3) (integer) 3 #执行SADD tag "C++" "Programming" "Mastering Series"
4) 1) "Mastering Series" #执行SMEMBERS tag
2) "C++"
3) "Programming"
事务其余操作:
1、DISCARD
取消事务,放弃执行事务块内的所有命令。
该操作需要在事务执行前才有效。
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> SET greeting "hello"
QUEUED
redis 127.0.0.1:6379> DISCARD #取消事务
OK
2、 WATCH key [key ...]
当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的。
如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断
redis> WATCH greeting #对于每个键来说,时间复杂度总是O(1)
OK
3、UNWATCH
取消 WATCH 命令对所有 key 的监视。
redis 127.0.0.1:6379> UNWATCH
OK
Redis为什么不支持回滚
- 首先看redis事务运行方式,只有在事务中命令有语法错误时,才会执行失败,这在将命令批量放入的环节就能发现问题。、
- 其次可能是因为向redis中放入不符合其数据类型的数据,这一般是由于程序原因,在程序开发期间会被发现。
- Reids程序内部开发简化,也因此不需要回滚能力。并且事务回滚并不能解决任何程序错误。程序错误需要程序员去解决处理。(逻辑性问题了)
这些程序错误不大可能会进入生产环境,所以在开发Redis时选用更加简单和快速的方法,并没有实现错误回滚的功能。
Redis脚本
定义
Redis脚本也是事务型的。因此,你可以通过Redis事务实现的功能,同样也可以通过Redis脚本来实现,而且通常脚本更简单、更快速。
执行脚本命令:
EVAL script numkeys key [key ...] arg [arg ...]
参数说明:
EVAL script numkeys key [key ...] arg [arg ...]
script: 参数是一段 Lua 5.1 脚本程序。脚本不必(也不应该)定义为一个 Lua 函数。
numkeys: 用于指定键名参数的个数。
key [key ...]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些
键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2]
,以此类推)。
arg [arg ...]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类
似( ARGV[1] 、 ARGV[2] ,诸如此类)。
redis 127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
1) "key1"
2) "key2"
3) "first"
4) "second"
脚本示例:
if redis.call(“EXISTS”,KEY[1])== 1 then
return redis.call(“INCERBY”,KEY[1],ARGV[]1)
else
return redis.call("SET",KEYS[1],ARGV[1])
end
执行脚本语句:
redis 127.0.0.1:6379> eval /you_path/script.lua jack , 2
脚本其余命令:
1、SCRIPT EXISTS script [script ...]
查看指定的脚本是否已经被保存在缓存当中。
2、SCRIPT FLUSH
从脚本缓存中移除所有脚本。
3、SCRIPT LOAD script
将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。
4、SCRIPT KILL
杀死当前正在运行的 Lua 脚本。
redis 127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'" # 载入一个脚本
"232fd51614574cf0867b83d384a5e898cfd24e5a"
redis 127.0.0.1:6379> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a
1) (integer) 1
redis 127.0.0.1:6379> SCRIPT FLUSH # 清空缓存
OK
redis 127.0.0.1:6379> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a
1)(integer) 0
redis 127.0.0.1:6379> SCRIPT KILL
OK
Redis连接:(连接数据库)
基本命令:
1、 AUTH password
验证密码是否正确
redis 127.0.0.1:6379> AUTH PASSWORD #密码错误返回错误信息
(error) ERR Client sent AUTH, but no password is set
redis 127.0.0.1:6379> CONFIG SET requirepass "mypass"
OK
redis 127.0.0.1:6379> AUTH mypass
Ok
2、ECHO message
打印字符串
redis 127.0.0.1:6379> ECHO "Hello World"
"Hello World"
3、PING
查看服务是否运行
# 客户端和服务器连接正常
redis 127.0.0.1:6379> PING
PONG
# 客户端和服务器连接不正常(网络不正常或服务器未能正常运行)
redis 127.0.0.1:6379> PING
Could not connect to Redis at 127.0.0.1:6379: Connection refused
4、QUIT
关闭当前连接
redis 127.0.0.1:6379> QUIT
OK
5、SELECT index
切换到指定的数据库
redis 127.0.0.1:6379> SET db_number 0 # 默认使用 0 号数据库
OK
redis 127.0.0.1:6379> SELECT 1 # 使用 1 号数据库
OK
6、CONFIG get requirepass
查看客户端连接到 redis 服务是否设置了密码
127.0.0.1:6379> CONFIG get requirepass #获取密码
1) "requirepass"
2) "" #密码为空
7、CONFIG get requirepass “要设置的密码”
该命令可以设置密码,密码设置完后可以AUTH “设置的密码“,进行验证
127.0.0.1:6379> CONFIG set requirepass "runoob"
OK
IDEA中Redis连接数据库:
连接方式:
1.jedis直连
2.jedis连接池
3.spring data redis集成连接
Redis 数据备份与恢复
基本命令:
1、Save备份数据库
将在 redis 安装目录中创建dump.rdb文件
redis 127.0.0.1:6379> SAVE
OK
2、Bgsave在后台备份数据
127.0.0.1:6379> BGSAVE
Background saving started #显示开启了后台备份
3、CONFIG获取redis目录
恢复数据,将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。
redis 127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/usr/local/redis/bin"
Redis客户端连接
1、首先,客户端 socket 会被设置为非阻塞模式,因为 Redis 在网络事件处理上采用的是非阻塞多路复用模型。
2、然后为这个 socket 设置 TCP_NODELAY 属性,禁用 Nagle 算法
3、然后创建一个可读的文件事件用于监听这个客户端 socket 的数据发送
最大连接数设置:
最大连接数的值是maxclients来设置的,默认值是10000,可以在redis.conf设置。
config get maxclients #config查看最大连接数
1) "maxclients"
2) "10000"
客户端基本命令:
1、CLIENT LIST
返回连接到 redis 服务的客户端列表
2、CLIENT SETNAME
设置当前连接的名称
3、CLIENT GETNAME
获取通过 CLIENT SETNAME 命令设置的服务名称
4、CLIENT PAUSE
挂起客户端连接,指定挂起的时间以毫秒计
5、CLIENT KILL
关闭客户端连接
Redis管道技术:
使用管道技术原因
Redis客户端和服务器之间使用的是TCP协议通信,所以无论发送请求还是接收响应必须经过网络传输,在tcp连接过程中,客户端服务端是阻塞的一问一答通信.
适用场景:
当短时间内发送大量对结果互不依赖对结果响应也无需立刻获得那么"管道(pipeline)"可以来充当批处理的工具
管道技术原理说明:使用管道时,客户端可以一次发送多条命令,这样在TCP连接中减少了"交互往返"的时间,并且服务端同一返回结果,多个命令只会进行一次read()和wrtie()系统调用,因此使用管道会提升Redis服务器处理命令的速度,随着管道中命令的增多,服务器每秒处理请求的数量会线性增长。
缺点:
当客户端用管道发送多条数据,服务器会将数据放入队列中,会消耗一定内存,所以管道命令的数量不宜太多。
实例:
public class JedisDemo {
private static int COMMAND_NUM = 1000;
private static String REDIS_HOST = "127.0.0.1";
public static void main(String[] args) {
Jedis jedis = new Jedis(REDIS_HOST, 6379);
withoutPipeline(jedis);
withPipeline(jedis);
}
private static void withoutPipeline(Jedis jedis) { //不使用管道技术连接
Long start = System.currentTimeMillis();
for (int i = 0; i < COMMAND_NUM; i++) {
jedis.set("no_pipe_" + String.valueOf(i), String.valueOf(i), SetParams.setParams().ex(60));
}
long end = System.currentTimeMillis();
long cost = end - start;
System.out.println("withoutPipeline cost : " + cost + " ms");
}
private static void withPipeline(Jedis jedis) { //使用管道技术连接
Pipeline pipe = jedis.pipelined();
long start_pipe = System.currentTimeMillis();
for (int i = 0; i < COMMAND_NUM; i++) {
pipe.set("pipe_" + String.valueOf(i), String.valueOf(i), SetParams.setParams().ex(60));
}
pipe.sync(); // 获取所有的response
long end_pipe = System.currentTimeMillis();
long cost_pipe = end_pipe - start_pipe;
System.out.println("withPipeline cost : " + cost_pipe + " ms");
}
}
Redis的内容好多呀,好难好难,不过都还只入了门,后面怎么还有这么多呀QAQ



