在CentOS7中安装redis
centos7中的epel源中有redis的安装包,如果系统中还没有安装epel源,先通过下面的命令安装
1 2 |
yum install -y epel-release |
安装好后就可以查询是否有redis包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[root@centos7-server ~]# yum info redis ... Available Packages Name : redis Arch : x86_64 Version : 3.2.12 Release : 1.el7 Size : 544 k Repo : epel/x86_64 Summary : A persistent key-value database URL : http://redis.io License : BSD Description : Redis is an advanced key-value store. It is often referred to as a data ..... |
安装运行redis
确认系统有redis安装包,只需要简单使用yum安装即可
1 2 |
yum install -y redis |
通过yum安装的redis支持systemd的启动方式,因此可以使用systemctl启动redis服务。
redis的默认启动文件是/etc/redis.conf
。
1 2 |
systemctl start redis |
redis安装包包含4个可执行程序,分别是
- redis-server redis服务器端,可用于启动redis服务
- redis-cli redis客户端,用于连接redis服务,并执行命令
- redis-benchmark 性能测试工具
- redis-check-aof aof文件检查工具
- redis-check-rdb rdb文件检查工具
除了使用systemd启动redis外,还可以使用redis-server命名
1 2 |
redis-server /etc/redis.conf |
连接redis
使用redis-cli连接redis服务
1 2 3 |
[root@centos7-server ~]# redis-cli -h 127.0.0.1 -p 6379 127.0.0.1:6379> |
如果所有参数都是默认的,可以直接运行redis-cli
1 2 3 |
[root@centos7-server ~]# redis-cli 127.0.0.1:6379> |
redis默认开启16个数据库,从0~15,可以在配置文件中修改。默认数据库是0号数据库。
获取数据库信息
使用redis-cli命令连接到redis后,可以使用info命令查看redis数据库的相关信息。
1 2 |
127.0.0.1:6379> info |
命令运行后会列出所有section的信息,也可以单独检查每个section的信息,例如
1 2 3 4 5 6 7 |
127.0.0.1:6379> info clients # Clients connected_clients:1 client_longest_output_list:0 client_biggest_input_buf:0 blocked_clients:0 |
info命令列出的内容太多,不便于查看,可以通过管道和其他命令一起使用
1 2 |
[root@centos7-server ~]# redis-cli info | less |
redis的数据类型和常用操作
redis是以键值对形式保存数据的,因此,所有数据都是通过key来获取和设置。
字符串
redis中所有非复杂类型的数据都是字符串,即使复杂数据类型最终保存的都是字符串数据。
set和get命令
set命令语法: set key value
get命令语法: get key
set命令用来添加一个键值,get命令则用于获取值。例如
1 2 3 4 5 |
127.0.0.1:6379> set foo bar #添加一个键foo,它的值是bar OK 127.0.0.1:6379> get foo #获取键foo的值 "bar" |
redis中没有数字类型,可以使用type
命令检查一个值的类型
1 2 3 4 5 6 7 |
127.0.0.1:6379> set age 10 OK 127.0.0.1:6379> get age "10" 127.0.0.1:6379> type age string |
incr和decr
虽然redis没有数字类型,但是我们依然可以像数字一样操作数字字符串。例如自增(incr)和自减(decr)操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
127.0.0.1:6379> set age 1 #age初始值为1 OK 127.0.0.1:6379> get age "1" 127.0.0.1:6379> incr age #age值增加1 (integer) 2 127.0.0.1:6379> get age "2" 127.0.0.1:6379> decr age #age值减小1 (integer) 1 127.0.0.1:6379> get age "1" |
incrby(incrbyfloat)和decrby
incr和decr的步进(递增/减值)永远都是1,incrby和decrby则可以设置一个不同的步进。
1 2 3 4 5 6 7 8 9 10 11 |
127.0.0.1:6379> set age 1 #age初始值1 OK 127.0.0.1:6379> incrby age 3 #age值加3 (integer) 4 127.0.0.1:6379> get age "4" 127.0.0.1:6379> decrby age 2 #age值减2 (integer) 2 127.0.0.1:6379> get age "2" |
incrbyfloat用于操作浮点数
1 2 3 4 5 |
127.0.0.1:6379> incrbyfloat age 1.5 "3.5" 127.0.0.1:6379> incrbyfloat age -0.5 "3" |
由于redis中没有decrbyfloat方法,因此减去一个浮点数必须通过加一个负浮点数的方式。
strlen和getrange
strlen用于获取值的长度,getrange则用于获取字符串的一个子串。
1 2 3 4 5 6 7 8 9 10 11 |
127.0.0.1:6379> set greeting "hello world" OK 127.0.0.1:6379> get greeting "hello world" 127.0.0.1:6379> strlen greeting (integer) 11 127.0.0.1:6379> getrange greeting 0 4 "hello" 127.0.0.1:6379> getrange greeting 0 -1 #获取整个字符串内容 "hello world" |
append
append命令用于追加一个字符串到一个key的结尾
1 2 3 4 5 6 7 |
127.0.0.1:6379> set greeting hello OK 127.0.0.1:6379> append greeting " world" (integer) 11 127.0.0.1:6379> get greeting "hello world" |
expire、persist和ttl
expire和persist是一对相反的命令,expire用于设置一个key的过期时间,而persist则设置一个key永不过期。
ttl用于查询key目前的生存期,如果key是一个永不过期的key,那么ttl返回-1。
1 2 3 4 5 6 7 8 9 10 11 |
127.0.0.1:6379> ttl age #age默认永不过期 (integer) -1 127.0.0.1:6379> expire age 60 #设置age60秒后过期 (integer) 1 127.0.0.1:6379> ttl age #age生存期剩余58秒 (integer) 58 127.0.0.1:6379> persist age #重新设置age用不过期 (integer) 1 127.0.0.1:6379> ttl age #永不过期的key ttl返回值为-1 (integer) -1 |
列表
列表是一个双向的栈结构,添加数据就是压栈(push),获取数据就是出栈(pop)。
lpush和rpush
1 2 3 4 5 6 7 8 9 10 |
127.0.0.1:6379> lpush season spring summer autumn winter (integer) 4 127.0.0.1:6379> llen season (integer) 4 127.0.0.1:6379> lrange season 0 -1 1) "winter" 2) "autumn" 3) "summer" 4) "spring" |
创建一个名为season的列表,并添加4个元素,我们使用的是lpush(left push),也就是说从spring开始入栈,栈结构的特征是后进先出,因此,栈顶(第一个元素)是winter,它是最后一个被压入栈的元素。
再来看一下rpush
1 2 3 4 5 6 7 8 |
127.0.0.1:6379> rpush season spring summer autumn winter (integer) 4 127.0.0.1:6379> lrange season 0 -1 1) "spring" 2) "summer" 3) "autumn" 4) "winter" |
从结果可以看出,数据从winter开始入栈(从右往左),因此sping是最后一个被压栈的元素,所以它处于栈顶。
lpop和rpop
lpop和rpop是和push相反的命令,用于把元素弹出列表。
1 2 3 4 5 6 7 8 9 10 11 |
127.0.0.1:6379> lrange season 0 -1 1) "spring" 2) "summer" 3) "autumn" 4) "winter" 127.0.0.1:6379> lpop season # 弹出栈左边的元素 "spring" 127.0.0.1:6379> rpop season #弹出栈右边的元素 "winter" |
lset
设置指定索引的元素的值,索引从0开始
1 2 3 |
127.0.0.1:6379> lset season 3 win #把winter设置为win OK |
lrem
移除列表中指定数量的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
127.0.0.1:6379> lpush direction east east east south west north (integer) 6 127.0.0.1:6379> lrange direction 0 -1 1) "north" 2) "west" 3) "south" 4) "east" 5) "east" 6) "east" 127.0.0.1:6379> lrem direction 2 east #删除direction中的2个east (integer) 2 127.0.0.1:6379> lrange direction 0 -1 #原来的3个east现在只有1个 1) "north" 2) "west" 3) "south" 4) "east" |
linsert
在指定位置插入元素
1 2 3 4 5 6 7 8 9 10 11 12 |
127.0.0.1:6379> lrange direction 0 -1 1) "north" 2) "south" 3) "east" 127.0.0.1:6379> linsert direction before south west #也可以指定after 例如 after north (integer) 4 127.0.0.1:6379> lrange direction 0 -1 1) "north" 2) "west" 3) "south" 4) "east" |
集合
集合中的元素必须是唯一的,即元素不能重复,插入的重复元素会被自动移除。
默认的集合是无序的。
sadd
1 2 3 4 5 6 7 8 |
127.0.0.1:6379> sadd season spring spring summer autumn autumn winter (integer) 4 127.0.0.1:6379> smembers season 1) "winter" 2) "spring" 3) "summer" 4) "autumn" |
往集合添加元素的时候我们故意有重复元素,但是只有4个元素被成功添加进去,重复的被去掉了。
scard
计算集合中元素的数量
1 2 3 |
127.0.0.1:6379> scard season (integer) 4 |
smembers
用于查看集合中的元素。
1 2 3 4 5 6 |
127.0.0.1:6379> smembers season 1) "winter" 2) "spring" 3) "autumn" 4) "summer" |
sismember
判断元素是否是集合中的一部分
1 2 3 4 5 |
127.0.0.1:6379> sismember season winter #winter是season的元素 (integer) 1 127.0.0.1:6379> sismember season east #east不是season的元素 (integer) 0 |
sunion和sinter
分别用于计算集合的并集和交集
计算并集
1 2 3 4 5 6 7 8 9 10 |
127.0.0.1:6379> sadd season1 spring summer (integer) 2 127.0.0.1:6379> sadd season2 autumn winter (integer) 2 127.0.0.1:6379> sunion season1 season2 1) "winter" 2) "spring" 3) "summer" 4) "autumn" |
计算交集
1 2 3 4 5 6 7 |
127.0.0.1:6379> sadd season1 spring winter autumn (integer) 3 127.0.0.1:6379> sadd season2 summer winter (integer) 2 127.0.0.1:6379> sinter season1 season2 #season1和season2共有的元素是winter 1) "winter" |
sdiff
计算差集
1 2 3 4 5 6 7 8 9 10 11 12 |
127.0.0.1:6379> sadd season1 spring winter autumn (integer) 3 127.0.0.1:6379> sadd season2 summer winter (integer) 2 127.0.0.1:6379> sinter season1 season2 1) "winter" 127.0.0.1:6379> sdiff season1 season2 #season1比season2多了spring和autumn 1) "spring" 2) "autumn" 127.0.0.1:6379> sdiff season2 season1 #season2比season1多了summer 1) "summer" |
有序集合
有序集合中元素的保存顺序按照添加时给定的权重排序。
zadd
添加元素
1 2 3 4 5 6 7 8 9 10 |
127.0.0.1:6379> zadd season 1 spring 2 summer 3 autumn 4 winter #添加时必须带上权重 (integer) 4 127.0.0.1:6379> zcard season (integer) 4 127.0.0.1:6379> zrange season 0 -1 #获取集合中的所有元素 1) "spring" 2) "summer" 3) "autumn" 4) "winter" |
权重越少排名越前。
zrem
移除有序集合中的元素
1 2 3 |
127.0.0.1:6379> zrem direction east (integer) 1 |
zscore
获取指定元素的权重
1 2 3 |
127.0.0.1:6379> zscore direction west "3" |
zrange和zrevrange
获取集合中的元素,前者先输出权重低的,后者先输出权重高的。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
127.0.0.1:6379> zadd direction 2 east 1 west 3 south 4 north (integer) 4 127.0.0.1:6379> zrange direction 0 -1 1) "west" 2) "east" 3) "south" 4) "north" 127.0.0.1:6379> zrevrange direction 0 -1 1) "north" 2) "south" 3) "east" 4) "west" |
zintersotre和zunionstore
取交集和并集,并把结果保存到一个新的集合中去
取并集
1 2 3 4 5 6 7 8 9 10 11 |
127.0.0.1:6379> zadd direction1 1 east 2 north 127.0.0.1:6379> zadd direction2 1 sourth 2 west (integer) 2 127.0.0.1:6379> zunionstore newdirection 2 direction1 direction2 (integer) 4 127.0.0.1:6379> zrange newdirection 0 -1 1) "east" 2) "sourth" 3) "north" 4) "west" |
取交集
1 2 3 4 5 6 7 8 9 10 |
127.0.0.1:6379> zadd direction1 1 east 2 north 3 west (integer) 3 127.0.0.1:6379> zadd direction2 1 north 2 west 3 south (integer) 3 127.0.0.1:6379> zinterstore interdirection 2 direction1 direction2 (integer) 2 127.0.0.1:6379> zrange interdirection 0 -1 1) "north" 2) "west" |
散列
散列数据类型中允许一个key对应多个字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
127.0.0.1:6379> hset user name jack #设置字段name的值为jack (integer) 1 127.0.0.1:6379> hget user name #获取字段name的值 "jack" 127.0.0.1:6379> hset user age 20 #设置字段age的值为20 (integer) 1 127.0.0.1:6379> hget user age "20" 127.0.0.1:6379> hgetall user #获取user中所有字段的值 1) "name" 2) "jack" 3) "age" 4) "20" |
hmset和hmget
hmset设置key中多个字段的值,hmget获取多个字段的值
1 2 3 4 5 6 |
127.0.0.1:6379> hmset user1 name tom age 30 gender male OK 127.0.0.1:6379> hmget user1 name age #获取name和age的值 1) "tom" 2) "30" |
hkeys
获取hash中所有的key
1 2 3 4 5 |
127.0.0.1:6379> hkeys user1 1) "name" 2) "age" 3) "gender" |
hexists
hash中是否存在指定字段
1 2 3 |
127.0.0.1:6379> hexists user1 gender (integer) 1 |
hdel
删除hash中指定字段
1 2 3 4 5 6 7 8 |
127.0.0.1:6379> hdel user1 gender (integer) 1 127.0.0.1:6379> hgetall user1 1) "name" 2) "tom" 3) "age" 4) "30" |
hlen
hash中有多少个字段
1 2 3 |
127.0.0.1:6379> hlen user1 #共有2个字段,分别时name和age (integer) 2 |
消息发布和订阅
publish和subscribe用于消息发布和订阅
subscribe
订阅指定的频道,subscribe可先于publish运行
1 2 3 4 5 6 7 |
127.0.0.1:6379> subscribe news Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "news" 3) (integer) 1 |
命令运行后处于阻塞状态,等待news频道发布消息。
publish
publish用于发布消息到指定频道下。现在通过另一个终端发布一个消息
1 2 3 |
127.0.0.1:6379> publish news "you have a new message" (integer) 1 |
这个时候,订阅者就接收到消息发布者的消息
1 2 3 4 5 6 7 8 9 |
127.0.0.1:6379> subscribe news Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "news" 3) (integer) 1 1) "message" #消息从这里开始 2) "news" 3) "you have a new message" |
事务
redis支持事务,但和传统的关系型数据库不同,redis的事务锁采用的是乐观锁:即事务运行的时候不预先锁定对象,而是观察对象是否已经改变,如果对象已经改变,则事务不执行。
multi和exec
开始一个事务,执行的事务会先放到队列里面,直到exec命令执行后才运行队列中的事务。使用经典的银行账号为例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
127.0.0.1:6379> hmset user1 name jack account 500 #添加两个账户,账号初始值为500 OK 127.0.0.1:6379> hmset user2 name tom account 500 OK 127.0.0.1:6379> multi #开始事务 OK 127.0.0.1:6379> hincrby user1 account -100 #user1账号减去100 QUEUED #提示事务已经放到队列 127.0.0.1:6379> hincrby user2 account 100 #user2账号加上100 QUEUED #队列已放到队列 127.0.0.1:6379> exec #执行事务 1) (integer) 400 2) (integer) 600 |
获取执行事务后各自的银行余额
1 2 3 4 5 |
127.0.0.1:6379> hget user1 account "400" 127.0.0.1:6379> hget user2 account "600" |
watch
另一个经典问题是买票,多个人抢票。
- 假设当前只有一张车票
- 使用watch观察车票是否有变动
- 开始事务
- 车票已经变化(即使ticket的值不设置为0)
- 把事务放进队列
- 执行事务(发现事务已经无法执行,原因是我们监视的值已经变化)
watch的作用是:当监视的值发生变化,就会通知事务,最终结果是事务执行失败,确保事务的安全性和一致性。
转载请注明:Pure nonsense » redis入门