一.概括
1.Redis是什么?
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
2.Redis能干什么
- 内存储存、持久化、内存中的数据是断电及失、所以说持久化很重要!(rdb、aof)
- 效率高、可以用于告诉缓存
- 发布订阅系统
- 地图信息分析
- 计时器、计数器、(数据浏览量)
3.Redis特性
- 持久化
-
多样化数据库
-
集群
-
事务
4.Redis官网
二.安装Redis
1.Windows安装
下载地址:Release 3.2.100 · microsoftarchive/redis (github.com)
下载后直接解压获得
双击 redis-server.exe
启动Redis服务器
双击redis-cli.exe运行redis客户端
这是我们就可以使用但是我们一般在Linu上使用
2.Linux安装
- 我们去官网下载安装包
- 上传到opt目录下
- 输入tar -zxvf 安装包 解压安装包
- 进入解压出来的目录
- 环境安装
yum -y install gcc-c++ 学习Linux时已安装过 gcc -v 查看信息 make 配置全部环境 make install
- redis的默认安装路径在 /usr/local/bin
- 在/usr/local/bin下新建我们自己的目录 mkdir jconfig
- cp /opt/redis-6.0.6/redis.conf jconfig 把redis.config移动我们新建的包下
- redis默认不是后台启动的,需要我们去修改配置文件 vim redis.conf
daemonize原本是no,我们改为yes就行
-
redis-server jconfig/redis.conf 启动redis
-
redis-cli -p 6379 进行连接测试
-
ping 查看是否启动成功,返回pong就是启动成功,就可以使用了
-
shutdown 关闭redis
-
exit 退出redis
三.性能测试
1.*redis-benchmark是一个官方自带的性能测试工具
redis-benchmark测试工具可选参数如下·:
2.测试
# 测试:100个并发连接 100000请求 需要在/usr/local/bin 下执行
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
四.基础知识
1.redis有16个数据库分别是DB0~DB15,默认使用的是DB0,
- select 数字 切换到数字的数据库
- dbsize 可以查看当前数据库的大小(大小取决于有多少个key)
- keys * 查看所有的key
- flushdb 清空当前数据库中的内容。
- flushall 清空所有数据库中的内容。
2.redis为什么是单线程的?
redis是基于内存的操作,CPU不是redis的性能瓶颈而是机器内存和网络带宽,所以单线程可以满足redis的的需求就是用了单线程。
3.redis是单线程为什么还这么快?
误区1:高性能的服务器一定是多线程的?
误区2:多线程(CPU上下文会切换!)一定比单线程效率高!
Redis是将所有的数据放在内存中的,所以说使用单线程去操作效率是最高的,多线程(CPU上下文会切换:耗时的操作!),对于内存系统来说如果没有上下文切换效率是最高的,多次读写都是在一个CPU上在内存存储数据情况下单线程就是最佳的方案。
五.五大基本数据类型
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。
Redis-key:在redis中无论什么数据类型,在数据库中都是以key-value形式保存,通过进行对Redis-key的操作,来完成对数据库中数据的操作。
- exists key 判断键是否存在 返回1表示存在返回0表示不存在
- del key 删除键值对
- move key db 将键值对移动到指定数据库
- pepire key second 设置键值对的过期时间
- ttl key 查看剩余过期时间 如果存在没设置过期时间返回-1,设置过期时间 已过期或者这个数据不存在会返回-2
- type key 查看value的数据类型
1.String (字符串)
命令 | 描述 | 示例 |
---|---|---|
APPEND key value |
向指定的key的value后追加字符串 | 127.0.0.1:6379> set name jiu OK 127.0.0.1:6379> append name qi (integer) 5 127.0.0.1:6379> get name "jiuqi” |
INCR/DECR key |
将指定key的value数值进行+1/-1(仅对于数字) | 127.0.0.1:6379> set age 3 127.0.0.1:6379> incr age "4" 127.0.0.1:6379> decr age "3" |
INCRBY/DECRBY key n |
按指定的步长对数值进行加减 | 127.0.0.1:6379> incrby age 5 "8" 127.0.0.1:6379> decrby age 3 "5" |
INCRBYFLOAT key n |
为数值加上浮点型数值 | 127.0.0.1:6379> incrbyfloat age 3.3 "8.3" |
STRLEN key |
获取key保存值的字符串长度 | 127.0.0.1:6379> get name "jiuqi" 127.0.0.1:6379> strlen name (integer) 5 |
GETRANGE key start end |
按起止位置获取字符串(闭区间,起止位置都取) | 127.0.0.1:6379> get name "jiuqi" 127.0.0.1:6379> getrange name 2 4 |
SETRANGE key offset value |
用指定的value 替换key中 offset开始的值 | 127.0.0.1:6379> setrange name 3 jiu 127.0.0.1:6379> get name "jiujiu" |
GETSET key value |
将给定 key 的值设为 value ,并返回 key 的旧值(old value)。 | 127.0.0.1:6379> getset name jiuqi "jiujiu" |
SETNX key value |
仅当key不存在时进行set | 127.0.0.1:6379> setnx name jiuqi (integer) 0 127.0.0.1:6379> setnx name1 jiuqi (integer) 1 |
SETEX key seconds value |
set 键值对并设置过期时间 | 127.0.0.1:6379> setex name1 30 name OK 127.0.0.1:6379> ttl name1 (integer) 26 |
MSET key1 value1 [key2 value2..] |
批量set键值对 | 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 |
MSETNX key1 value1 [key2 value2..] |
批量设置键值对,仅当参数中所有的key都不存在时执行 | 127.0.0.1:6379> msetnx k1 v1 k4 v4 (integer) 0 127.0.0.1:6379> msetnx k4 v4 k5 v5 |
MGET key1 [key2..] |
批量获取多个key保存的值 | 127.0.0.1:6379> mget k1 k2 k4 k5 1) "v1" 2) "v2" 3) "v4" 4) "v5" |
set user:1 {name:baize,age:11} | json字符串设置一个对象 | 127.0.0.1:6379> set user:1 {name:baize,age:11} |
mset 类型:id:key value 类型:id:key value | 设置一个对象· | 127.0.0.1:6379> mset user:1:name baize user:1:age 11 |
String类似的使用场景:
- 计数器
- 统计多单位的数量 uid:123666:follow 0
- 粉丝数
- 对象存储缓存
2.List(列表)
Redis列表是简单的字符串列表,按照插入顺序排序你可以添加一个元素到列表的头部(左边)或者尾部(右边),一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)
redis列表可以经过规则定义将其变为队列、栈、双端队列等
-
list实际上是一个链表,before Node after , left, right 都可以插入值
-
如果key不存在,则创建新的链表
-
如果key存在,新增内容
-
如果移除了所有值,空链表,也代表不存在
-
在两边插入或者改动值,效率最高!修改中间元素,效率相对较低
命令 | 描述 | 示例 |
---|---|---|
lpush/rpush 列表 value1[value2..] | 从左边或者右边向列表中添加值 | 127.0.0.1:6379[1]> lpush list one (integer) 1 127.0.0.1:6379[1]> lpush list two (integer) 2 127.0.0.1:6379[1]> lpush list three (integer) 3 127.0.0.1:6379[1]> lpush list 1 2 3 (integer) 6 |
lrange 列表 start end |
获取list元素 | 127.0.0.1:6379[1]> lrange list 0 -1 1) "3" 2) "2" 3) "1" 4) "three" 5) "two" 6) "one" 127.0.0.1:6379[1]> lrange list 1 2 1) "two" 2) "one" |
lpop/rpop 列表 | 从左边或者右边移除列表中的一个值 | 127.0.0.1:6379[1]> lpop list "3" 127.0.0.1:6379[1]> rpop list "one" |
lindex 列表 index | 通过索引获取列表元素 | 127.0.0.1:6379[1]> lindex list 2 "three" |
llen 列表 | 查看列表长度 | 127.0.0.1:6379[1]> llen list (integer) 4 |
lrem 列表 移除数量 value | 移除具体的元素 | 127.0.0.1:6379[1]> lrem list 1 two (integer) 1 |
ltrim key start end | 通过下标保留指定范围内的元素 | 127.0.0.1:6379[1]> ltrim list 1 2 OK |
rpoplpush source destination | 将列表的尾部(右)最后一个值弹出,并返回,然后加到另一个列表的头部 | 127.0.0.1:6379[1]> rpoplpush list mylist "three" 127.0.0.1:6379[1]> lrange mylist 0 -1 1) "three" |
lset key index value | 通过索引为元素设值,需要索引有值 | 127.0.0.1:6379[1]> lrange list 0 -1 127.0.0.1:6379[1]> lset list 1 first |
linsert key before|after pivot value | 在指定列表元素的前/后 插入value | 127.0.0.1:6379[1]> linsert list before two other (integer) 4 127.0.0.1:6379[1]> lrange list 0 -1 1) "one" 2) "other" 3) "two" 4) "three" |
blpop/brpop key1[key2] 等待时间 | 移出并获取列表的第一个/最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 | 127.0.0.1:6379[1]> brpop list 5 127.0.0.1:6379[1]> blpop name 1 |
3.set(集合)
命令 | 描述 | 示例 |
---|---|---|
sadd 集合 member1[member2..] | 向集合中无序增加一个/多个成员 | 127.0.0.1:6379[1]> sadd myset key1 |
scard 集合 | 获取集合的成元素数量 | 127.0.0.1:6379[1]> scard myset (integer) 3 |
smembers 集合 | 查询集合的所有成员 | 127.0.0.1:6379[1]> smembers myset 1) "key1" 2) "key2" 3) "key3" |
sismember 集合 元素 |
查询元素是否是集合的成员 | 127.0.0.1:6379[1]> sismember myset key1 (integer) 1 127.0.0.1:6379[1]> sismember myset key5 (integer) 0 |
srandmember 集合 count | 随机返回集合中count个成员,count缺省值为1 | 127.0.0.1:6379[1]> srandmember myset "key1" 127.0.0.1:6379[1]> srandmember myset 2 1) "key2" 2) "key3" |
spop 集合 count | 随机移除并返回集合中count个成员,count缺省值为1 | 127.0.0.1:6379[1]> spop myset "key3" 127.0.0.1:6379[1]> spop myset 2 1) "key1" 2) "key2" |
smove 集合1 集合2 元素 | 将集合1的元素移到集合2 | 127.0.0.1:6379[1]> smove myset1 myset2 key (integer) 1 127.0.0.1:6379[1]> smembers myset2 1) "key" |
srem key member1[member2..] | 移除集合中一个/多个成员 | 127.0.0.1:6379[1]> srem myset2 key (inteVger) 1 |
sdiff 集合1 集合2 | 返回所有集合的差集 | 127.0.0.1:6379[1]> smembers myset1 127.0.0.1:6379[1]> sdiff myset1 myset2 |
sinter 集合1 集合2 | 返回所有集合的交集 | 127.0.0.1:6379[1]> sinter myset1 myset2 1) "key3" |
sunion 集合1 集合2 | 返回所有集合的并集 | 127.0.0.1:6379[1]> sunion myset1 myset2 1) "key2" 2) "key5" 3) "key3" 4) "key1" 5) "key4" |
sinterstore 集合3 集合1 集合2 | 在sinter的基础上,存储结果到集合3中。 | 127.0.0.1:6379[1]> sinterstore myset3 myset1 myset2 (integer) 1 127.0.0.1:6379[1]> smembers myset3 1) "key3" |
4.hash(哈希)
Hash变更的数据user name age,尤其是用户信息之类的,经常变动的信息!Hash更适合于对象的存储,Sring更加适合字符串存储!
命令 | 描述 | 示例 |
---|---|---|
hset key field value | 将哈希表 key 中的字段 field 的值设置为 value | 127.0.0.1:6379[1]> hset myhash field1 one (integer) 1 |
hmset key field1 value1 [field2 value2..] | 同时将多个 field-value 添加到哈希表 key 中 | 127.0.0.1:6379[1]> hmset myhash field2 two field3 three OK |
hget key field value | 获取存储在哈希表中指定字段的值 | 127.0.0.1:6379[1]> hget myhash field1 "one" |
hmget key field1 [field2..] | 获取表中所有字段的值 | 127.0.0.1:6379[1]> hmget myhash field1 field2 field3 1) "one" 2) "two" 3) "three" |
hsetnx key field value | 只有在字段 field 不存在时,设置哈希表字段的值。 | 127.0.0.1:6379[1]> hsetnx myhash field1 (error) ERR wrong number of arguments for 'hsetnx' command 127.0.0.1:6379[1]> hsetnx myhash field4 four (integer) 1 |
hexists key field | 查看指定的字段在表中是否存在。 | 127.0.0.1:6379[1]> hexists myhash field4 (integer) 1 |
hgetall key | 获取在哈希表key 的所有字段和值 | 127.0.0.1:6379[1]> hgetall myhash 1) "field1" 2) "one" 3) "field2" 4) "two" 5) "field3" 6) "three" 7) "field4" 8) "four" |
hkeys key | 获取哈希表key中所有的字段 | 127.0.0.1:6379[1]> hkeys myhash 1) "field1" 2) "field2" 3) "field3" 4) "field4" |
hvals key | 获取哈希表中所有值 | 127.0.0.1:6379[1]> hvals myhash 1) "one" 2) "two" 3) "three" 4) "four" |
hlen | 获取哈希表中字段的数量 | 127.0.0.1:6379[1]> hlen myhash (integer) 4 |
hdel key field1 [field2..] | 删除哈希表key中一个/多个field字段 | 127.0.0.1:6379[1]> hdel myhash field4 field3 (integer) 2 |
hincrby key field n | 为哈希表 key 中的指定字段的整数值加上增量n,并返回增量后结果 一样只适用于整数型字段 | 127.0.0.1:6379[1]> hincrby myhash field4 2 (integer) 9 127.0.0.1:6379[1]> hincrby myhash field4 -2 (integer) 7 |
hincrbyfloat key field n | 为哈希表 key 中的指定字段的浮点数值加上增量 n。 | 127.0.0.1:6379[1]> hincrbyfloat myhash field4 0.9 "7.9" |
hmset 集合:id key1 value1 key2 vaue2 |
设置一个对象 | 127.0.0.1:6379[1]> hmset user:1 name jiuqi age 3 OK |
5.Zset(有序集合)
每个元素都会关联一个double类型的分数(score),redis正是通过分数来为集合中的成员进行从小到大的排序,score相同按字典顺序排序。有序集合的成员是唯一的但分数(score)却可以重复。
- set排序 存储班级成绩表 工资表排序!
- 普通消息,1.重要消息 2.带权重进行判断
- 排行榜应用实现,取Top N测试
命令 | 描述 | 示例 | |
---|---|---|---|
zadd key score member1 [score2 member2] | 向集合添加一个或多个成员 | 127.0.0.1:6379[1]> zadd salary 500 baize (integer) 1 |
|
zcard key | 获取有序集合的成员数 | 127.0.0.1:6379[1]> zcard salary (integer) 5 |
|
zcount key min max | 计算在集合中score在指定区间的成员数 | 127.0.0.1:6379[1]> zcount salary 0 2000 (integer) 4 |
|
zscore key member | 返回集合中成员的分数值 | 127.0.0.1:6379[1]> zscore salary baize "500" |
|
zincrby key n member | 集合中对指定成员的score加上n | 127.0.0.1:6379[1]> zincrby salary 5000 jiuqi "8000" |
|
zrank key member | 返回有序集合中指定成员的索引 | 127.0.0.1:6379[1]> zrank salary jiuqi (integer) 4 |
|
zrange key start end | 通过索引区间返回有序集合成指定区间内的成员,score从低到高 | 127.0.0.1:6379[1]> zrange salary 0 -1 1) "baize" 2) "ningyao" 3) "zuoyou" 4) "yabahu" 5) "jiuqi" |
|
zrevrange key start end | 通过索引区间返回有序集合成指定区间内的成员,score从高到低 | ||
zrangebyscore key min max | 通过分数返回集合指定区间内的成员 | 127.0.0.1:6379[1]> zrangebyscore salary 1000 3000 1) "ningyao" 2) "zuoyou" 3) "yabahu" |
|
zrem key member1 [member2..] | 移除集合中一个/多个成员 | 127.0.0.1:6379[1]> zrem salary yabahu (integer) 1 |
|
zremrangebyrank key start stop | 通过索引区间移除集合中成员 | 127.0.0.1:6379[1]> zremrangebyrank salary 0 3 (integer) 4 |
|
zremrangebyscore key min max | 通过score区间移除集合中成员 | 127.0.0.1:6379[1]> zremrangebyscore salary 0 3000 (integer) 2 |
|
zrevrangebyscore key max min | 返回集中指定score区间内的成员,从高到低排序 | 127.0.0.1:6379[1]> zrevrangebyscore salary 2000 1000 1) "yabahu" 2) "zuoyou" 3) "ningyao" |
|
zinterstore key numkeys key1 [key2 ..] | 计算给定的一个或多个集合的交集并将结果集存储在新的有序集合 key 中,numkeys:表示参与运算的集合数 | 127.0.0.1:6379[1]> zadd salary1 1000 ningyao 1500 zuoyou 2000 yabahu 1000 gucan 127.0.0.1:6379[1]> zadd salary 1000 ningyao 1000 yabahu 2000 zuoyou 10000 qijingchun |
六.三种特殊数据类型
1.Geospatial(地理位置)
经纬度的范围
- 经度从-180度到180度。
- 纬度从-85.05112878度到85.05112878度。
指定单位的参数 unit 必须是以下单位的其中一个:
-
m 表示单位为米。
-
km 表示单位为千米。
-
mi 表示单位为英里。
-
ft 表示单位为英尺。
Geospatial使用Zset保存的数据所有Zset的命令可以使用
命令 | 解释 | 示例 |
---|---|---|
geoadd key 经度 纬度 member [经度 纬度 member1..] | 将具体位置的经纬度存入一个集合 | 127.0.0.1:6379[1]> geoadd china:city 116.40 39.90 beijing (integer) 1 |
geopos key member [member..] | 获取集合中的一个/多个位置坐标 | 127.0.0.1:6379[1]> geopos china:city beijing 1) 1) "116.39999896287918091" 2) "39.90000009167092543" |
geodist key member1 member2 [unit] | 返回两个给定位置之间的距离。默认以米作为单位。 | 127.0.0.1:6379[1]> geodist china:city beijing shanghai "1067378.7564" |
georadius key longitude latitude radius m|km|mi|ft [WITHCOORD][WITHDIST] [WITHHASH] [COUNT count] | 以给定的经纬度为中心, 返回集合包含的位置当与中心的距离不超过给定最大距离的所有位置。 | 127.0.0.1:6379[1]> georadius china:city 110 30 1000 km withcoord 1) 1) "nanchang" 2) 1) "115.88999837636947632" 2) "28.66999910629679249" 2) 1) "hangzhou" 2) 1) "120.15000075101852417" 2) "30.2800007575645509" 3) 1) "zhengzhou" 2) 1) "113.65999907255172729" |
georadiusbymember key member radius... | 以给定的位置为中心, 返回集合包含的位置当与中心的距离不超过给定最大距离的所有位置。 | 127.0.0.1:6379[1]> georadiusbymember china:city beijing 1000 km 1) "zhengzhou" 2) "beijing" |
geohash key member1 [member2..] | 返回一个或多个位置经纬度的一维字符串。 | 127.0.0.1:6379[1]> geohash china:city shanghai hangzhou beijing |
2.Hyperloglog
- Redis HyperLogLog 是用来做基数统计的算法,其底层使用string数据类型。
- HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的并且是很小的,花费 12 KB 内存就可以计算接近 2^64 个不同元素的基数。
- 因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
- HyperLogLog有0.81%的错误率,如果允许容错就可以使用HyperLogLog
什么是基数?
- 数据集中不重复元素的个数
应用场景?
- 网页的访问量(UV):一个用户多次访问,也只能算作一个人。
- 传统实现是比较存储用户的id,当用户变多之后这种方式及其浪费空间。
命令 | 描述 | 示例 |
---|---|---|
pfadd key element1 [elememt2..] | 添加元素 | 127.0.0.1:6379> pfadd array a b c d e f f a c (integer) 1 |
pfcount key [key] | 返回集合基数 | 127.0.0.1:6379> pfcount array (integer) 6 |
pfmerge destkey sourcekey [sourcekey..] | 将多个集合合并为一个新的集合 | 127.0.0.1:6379> pfadd array1 f g h i j k (integer) 1 127.0.0.1:6379> pfmerge array2 array array1 OK 127.0.0.1:6379> pfcount array2 (integer) 11 |
3.BitMaps
BitMaps位图,数据结构都是操作二进制位进行记录的,就只有0和1两个状态
当信息状态只有两种情况时我们就可以使用BitMaps
命令 | 描述 | 示例 |
---|---|---|
setbit key offset value | 为指定key的offset位设置值 | 127.0.0.1:6379> setbit sing 0 1 (integer) 0 |
getbit key offset | 获取offset位的值 | 127.0.0.1:6379> getbit sing 0 (integer) 1 |
bitcount key [start end] | 不写[start end]就是统计offset被设置为1的key的数量,写可以指定统计范围按字节 | 127.0.0.1:6379> bitcount sing (integer) 6 |
七.事务
1.基本知识
Redis事务本质:一组命令的集合。每条命令都会被序列化,按顺序执行不允许其他命令进行干扰
事务的特点:一次性、顺序性、排他性
没有隔离级别,所有的命令在事务中并没有被执行只有发起执行命令时才会执行。
Redis的单条命令是保证原子性的,但是redis事务不能保证原子性,代码语法错误(编译时异常)所有的命令都不执行,代码逻辑错误 (运行时异常) 其他命令可以正常执行
2.redis执行事物的命令:
- 开启事务(multi)
- 命令入队(普通命令)
- 执行事务(exec)
- 取消事务(
discurd
) - 事务错误
开启事务
127.0.0.1:6379> multi
OK命令入队
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED执行事务
127.0.0.1:6379> exec
1) OK
2) OK
3) "v2"取消事务
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get k4
(nil)事务错误
码语法错误(编译时异常)所有的命令都不执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> getset k2
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
(nil)代码逻辑错误 (运行时异常) 其他命令可以正常执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) (error) ERR value is not an integer or out of range
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k1
"v1"
3.监控
悲观锁:很悲观,认为什么时候都会出现问题,无论做什么都会加锁
乐观锁:很乐观,认为什么时候都不会出现问题所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据,获取version更新的时候比较version。
Redis中使用watch对数据进行监控,相当于乐观锁。
正常执行
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20模拟多线程插队
线程一:
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 50
QUEUED
127.0.0.1:6379> get money
QUEUED
线程二:127.0.0.1:6379> incrby money 1000
(integer) 1100线程一:
127.0.0.1:6379> exec
(nil)解除锁定
unwatch
八.Jedis
Jedis是官方推荐的一款java操作redis数据库的工具