Redis 基本介绍
Redis 的安装
windows版 https://github.com/tporadowski/redis/releases
Linux版 https://redis.io/download/#redis-downloads
解压即可
Redis 操作的基本原理
Redis 的基本使用
Redis 安装好后,默认有 16 个数据库,初始默认使用 0 号库, 编号是 0…15
- 添加 key-val [set]
- 查看当前 redis 的 所有 key [keys *]
- 获取 key 对应的值. [get key]
- 切换 redis 数据库 [select index]
- 如何查看当前数据库的 key-val 数量 [dbsize]
- 清空当前数据库的 key-val 和清空所有数据库的 key-val [flushdb flushall]
Redis 的基本操作
Redis 的五大数据类型
Redis 的五大数据类型是: String(字符串) 、Hash (哈希)、List(列表)、Set(集合)和 zset(sorted set:有序集合)
String(字符串)
string 是 redis 最基本的类型,一个 key 对应一个 value。
string 类型是二进制安全的。除普通的字符串外,也可以存放图片等数据
redis 中字符串 value 最大是 512M
新增、修改、删除一个key
# 添加一个元素
127.0.0.1:6379> set address beijing
OK
# 获取一个元素
127.0.0.1:6379> get address
"beijing"
# 因为key address已存在,set就变成了修改操作
127.0.0.1:6379> set address shanghai
OK
127.0.0.1:6379> get address
"shanghai"
# 删除一个元素
127.0.0.1:6379> del address
(integer) 1
127.0.0.1:6379> get address
(nil)
127.0.0.1:6379>
设置一个10s过期的key
# 给key msg 设置10s过期
127.0.0.1:6379> setex msg 10 hello
OK
127.0.0.1:6379> get msg
"hello"
127.0.0.1:6379> get msg
"hello"
# 10s后 key msg 就被干掉了
127.0.0.1:6379> get msg
(nil)
127.0.0.1:6379>
同时操作一个或多个 key-value 对
# 同时设置多个键值对
127.0.0.1:6379> mset name1 tom name2 jack
OK
127.0.0.1:6379> get name1
"tom"
# 同时获取多个键值对
127.0.0.1:6379> mget name1 name2
1) "tom"
2) "jack"
127.0.0.1:6379>
Hash (哈希)
Redis hash 是一个键值对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
存放一个 User 信息
# 给key user1 设置属性 name 为 tom
127.0.0.1:6379> hset user1 name tom
(integer) 1
# 给key user1 设置属性 age 为 10
127.0.0.1:6379> hset user1 age 10
(integer) 1
# 获取key user1 的属性 name
127.0.0.1:6379> hget user1 name
"tom"
# 获取key user1 的属性 age
127.0.0.1:6379> hget user1 age
"10"
# 获取key user1 的全部属性
127.0.0.1:6379> hgetall user1
1) "name"
2) "tom"
3) "age"
4) "10"
127.0.0.1:6379>
一次性来设置多个 filed 的值和返回多个 field 的值
# 给key user2 同时设置属性 name 为 jack age 为 20
127.0.0.1:6379> hmset user2 name jack age 20
OK
# 获取key user2 的属性 name age
127.0.0.1:6379> hmget user2 name age
1) "jack"
2) "20"
127.0.0.1:6379>
统计一个 hash 有几个元素
127.0.0.1:6379> hlen user2
(integer) 2
查看哈希表的指定字段是否存在
# 判断key user2是否存在属性 name
127.0.0.1:6379> hexists user2 name
# 存在
(integer) 1
# 判断key user2是否存在属性 job
127.0.0.1:6379> hexists user2 job
# 不存在
(integer) 0
List(列表)
列表是简单的字符串列表,按照插入顺序排序
你可以添加一个元素到列表的头部(左边)或者尾部(右边),如果值全移除,对应的键也就消失了
List 本质是个链表, List 的元素是有序的,元素的值可以重复
向list中新增、修改、删除多个key
# 向list左边添加元素
127.0.0.1:6379> lpush city beijing shanghai shenzen
(integer) 3
# 获取city list 中从0开始到结尾的数据
127.0.0.1:6379> lrange city 0 -1
1) "shenzen"
2) "shanghai"
3) "beijing"
# 向list右边添加元素
127.0.0.1:6379> rpush city hangzhou
(integer) 4
127.0.0.1:6379> lrange city 0 -1
1) "shenzen"
2) "shanghai"
3) "beijing"
4) "hangzhou"
# 将list左边的一个元素取出
127.0.0.1:6379> lpop city
"shenzen"
# 将list右边的一个元素取出
127.0.0.1:6379> rpop city
"hangzhou"
127.0.0.1:6379> lrange city 0 -1
1) "shanghai"
2) "beijing"
# 删除list city
127.0.0.1:6379> del city
(integer) 1
127.0.0.1:6379> lrange city 0 -1
(empty list or set)
按下标访问list元素
127.0.0.1:6379> lpush listTest a b
(integer) 2
# 访问下标为0的元素
127.0.0.1:6379> lindex listTest 0
"b"
# 访问下标为1的元素
127.0.0.1:6379> lindex listTest 1
"a"
# 访问下标为2的元素 没有返回nil
127.0.0.1:6379> lindex listTest 2
(nil)
127.0.0.1:6379>
获取list长度
127.0.0.1:6379> llen listTest
(integer) 2
127.0.0.1:6379> lpop listTest
"b"
127.0.0.1:6379> llen listTest
(integer) 1
127.0.0.1:6379>
Set(集合)
Redis 的 Set 是 string 类型的无序集合。
底层是 HashTable 数据结构, Set 也是存放很多字符串元素,字符串元素是无序的,而且元素的值不能重复
用set存放多个Email数据
# 添加两个邮箱
127.0.0.1:6379> sadd emails tom@qq.com jack@163.com
(integer) 2
# 访问emails中的元素
127.0.0.1:6379> smembers emails
1) "jack@163.com"
2) "tom@qq.com"
# 添加一个邮箱kevin@qq.com
127.0.0.1:6379> sadd emails kevin@qq.com
(integer) 1
# 查看
127.0.0.1:6379> smembers emails
1) "jack@163.com"
2) "tom@qq.com"
3) "kevin@qq.com"
# 再次添加一个重复邮箱kevin@qq.com
127.0.0.1:6379> sadd emails kevin@qq.com
# 无法添加
(integer) 0
# 查看
127.0.0.1:6379> smembers emails
1) "jack@163.com"
2) "tom@qq.com"
3) "kevin@qq.com"
sismember[判断值是否是成员] srem [删除指定值]
# 查看现有元素
127.0.0.1:6379> smembers emails
1) "jack@163.com"
2) "tom@qq.com"
3) "kevin@qq.com"
# 判断集合中是否有元素 tom@qq.com
127.0.0.1:6379> sismember emails tom@qq.com
# 有
(integer) 1
# 判断集合中是否有元素 tom~@qq.com
127.0.0.1:6379> sismember emails tom~@qq.com
# 没有
(integer) 0
# 删除元素 tom@qq.com
127.0.0.1:6379> srem emails tom@qq.com
(integer) 1
# 查看
127.0.0.1:6379> smembers emails
1) "jack@163.com"
2) "kevin@qq.com"
ZSet(有序集合)
Redis zset(有序集合)中的成员是有序排列的,集合中的每一个成员都是字符串类型,并且不允许重复
有序集合中每个成员都会关联一个 double(双精度浮点数)类型的 score (分数值),Redis 正是通过 score 实现了对集合成员的排序。
有序集合(zset)使用了两种不同的存储结构,分别是 zipList(压缩列表)和 skipList(跳跃列表)
注意:在有序集合中,成员是唯一存在的,但是分数(score)却可以重复。有序集合的最大的成员数为 2^32 - 1
保存员工薪水的有序集合
#在有序集合中添加一个成员
127.0.0.1:6379> ZADD salary 4000 lucy
(integer) 1
#同时添加多个成员
127.0.0.1:6379> ZADD salary 5000 tom 6000 Helen 6500.50 Jack 3000 Smith
(integer) 4
#查询指定区间上的元素
127.0.0.1:6379> ZRANGE salary 0 4
1) "Smith"
2) "lucy"
3) "tom"
4) "Helen"
5) "Jack"
#降序查看指定区间上的元素
127.0.0.1:6379> ZREVRANGE salary 0 4
1) "Jack"
2) "Helen"
3) "tom"
4) "lucy"
5) "Smith"
#查看指定元素的分值
127.0.0.1:6379> ZSCORE salary lucy
"4000"
#查看所有元素和分值
127.0.0.1:6379> ZRANGE salary 0 4 WITHSCORES
1) "Smith"
2) "3000"
3) "lucy"
4) "4000"
5) "tom"
6) "5000"
7) "Helen"
8) "6000"
9) "Jack"
10) "6500.5"
#统计指定工资范围内的元素个数3000<=score<=5000
127.0.0.1:6379> ZCOUNT salary 3000 5000
(integer) 3
#表示3000<score<5000
127.0.0.1:6379> ZCOUNT salary (3000 (5000
(integer) 1
#返回指定工资范围内的score和成员,限制条件是跳过1个元素,返回2个元素。
127.0.0.1:6379> ZRANGEBYSCORE salary 3000 6000 WITHSCORES LIMIT 1 2
1) "lucy"
2) "4000"
3) "tom"
4) "5000"
#查看有序集合在指定字典区间内的成员的数
#其中 - 表示最小值,而 + 则表示最大值
127.0.0.1:6379> ZLEXCOUNT salary - +
(integer) 5
Golang 操作 Redis
安装第三方开源Redis 库
- 使用第三方开源的 redis 库: github.com/garyburd/redigo/redis
- 在使用 Redis 前,先安装第三方 Redis 库,在 GOPATH 路径下执行安装指令:
go get github.com/garyburd/redigo/redis
- 安装成功后,可以看到如下包
特别说明: 在安装 Redis 库前,确保已经安装并配置了 Git, 因为 是从 github 下载安装 Redis 库的, 需要使用到 Git。
Set/Get数据
package main
import (
"fmt"
"github.com/garyburd/redigo/redis" //引入redis包
)
func main() {
//通过go 向redis 写入数据和读取数据
//1. 链接到redis
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Println("redis.Dial err=", err)
return
}
defer conn.Close() //关闭..
//2. 通过go 向redis写入数据 string [key-val]
_, err = conn.Do("Set", "name", "tomjerry猫猫")
if err != nil {
fmt.Println("set err=", err)
return
}
//3. 通过go 向redis读取数据 string [key-val]
r, err := redis.String(conn.Do("Get", "name"))
if err != nil {
fmt.Println("set err=", err)
return
}
//因为返回 r是 interface{}
//因为 name 对应的值是string ,因此我们需要转换
//nameString := r.(string)
fmt.Println("操作ok ", r)
}
PS E:\GoProject> go run .\src\go_code\chapter18\redisdemo\main\
操作ok tomjerry猫猫
批量Set/Get 数据
_, err = c.Do("MSet", "name", "tom", "address", "北京")
r, err := redis.Strings(c.Do("MGet", "name", "address"))
for _, v := range r {
fmt.Println(v)
}
给数据设置有效时间
//给 name 数据设置有效时间为 10s
_, err = c.Do("expire", "name", 10)
操作List
_, err = c.Do("lpush", "heroList", "no1:宋江", 30, "no2:卢俊义", 28)
r, err := redis.String(c.Do("rpop", "heroList"))
Redis 链接池
通过 Golang 对 Redis 操作, 还可以通过 Redis 链接池, 流程如下
- 事先初始化一定数量的链接,放入到链接池
- 当 Go 需要操作 Redis 时,直接从 Redis 链接池取出链接即可
- 这样可以节省临时获取 Redis 链接的时间,从而提高效率
链接池使用的案例
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
//定义一个全局的pool
var pool *redis.Pool
//当启动程序时,就初始化连接池
func init() {
pool = &redis.Pool{
MaxIdle: 8, //最大空闲链接数
MaxActive: 0, // 表示和数据库的最大链接数, 0 表示没有限制
IdleTimeout: 100, // 最大空闲时间
Dial: func() (redis.Conn, error) { // 初始化链接的代码, 链接哪个ip的redis
return redis.Dial("tcp", "localhost:6379")
},
}
}
func main() {
//先从pool 取出一个链接
conn := pool.Get()
defer conn.Close()
_, err := conn.Do("Set", "name", "汤姆猫~~")
if err != nil {
fmt.Println("conn.Do err=", err)
return
}
//取出
r, err := redis.String(conn.Do("Get", "name"))
if err != nil {
fmt.Println("conn.Do err=", err)
return
}
fmt.Println("r=", r)
//如果我们要从pool 取出链接,一定保证链接池是没有关闭
//pool.Close()
conn2 := pool.Get()
_, err = conn2.Do("Set", "name2", "汤姆猫~~2")
if err != nil {
fmt.Println("conn.Do err~~~~=", err)
return
}
//取出
r2, err := redis.String(conn2.Do("Get", "name2"))
if err != nil {
fmt.Println("conn.Do err=", err)
return
}
fmt.Println("r=", r2)
//fmt.Println("conn2=", conn2)
}