(1).Redis 是 NoSQL 数据库,不是传统的关系型数据库,官网: https://redis.io/ 和http://redis.cn/
(2).Redis: REmote Dlctionary Sever(远程字典服务器), Redis 性能非常高,单机能够达到 15w qps,通常适合做缓存,也可以持久化
(3).完全开源免费的,高性能的(key-value)分布式内存数据库,基于内存运行并支持持久化的 NoSOL 数据库,是最热门的Nosql数据库之一,也称为数据结构服务器
总结: redis ( REmote Dlctionary Sever)是一个由 Salvatore Sanfilippo 编写的key-value 存储系统,它由 C 语言编写、遵守 BSO 协议、支持网络、可基于内存亦可持久化的日志型、 key-value 类型的数据库,并提供多种语言的 API.和 Memcached 类似,它支持存储的 value 类型相对更多,包括 string(字符串)、 Iist (链表)、 set (集合)、 zset ( sorted set 一有序集合)和 hash (哈希类型).这些数据类型都支持 push / pop 、 add / remove 及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上, redis 支持各种不同的方式排序.与 memcached 一样,为了保证效率,数据都是缓存在内存中。区别的是 redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步, redis 在3.0版本推出集群模式
源码部署
yum install gcc -y #安装c依赖
wget http://download.redis.io/redis-stable.tar.gz #下载稳定版本
tar zxvf redis-stable.tar.gz #解压
cd redis-stable
make PREFIX=/opt/app/redis install #指定目录编译
make install
下载后直接解压就有 Redis 的服务端程序( redis - server.exe )和客户端程序(redis.exe),直接双击即可运行
说明: Redis 安装好后,默认有 16 个数据库,初始默认使用0号库,编号是0,1,2,....,15
(1).添加key-val [set]
(2).查看当前redid的所有key [keys *]
(3).获取 key 对应的值 [get key]
(4).切换redis数据库库 [select index]
(5).如何查看当前数据库的key-val数量 [dbsize]
(6).清空当前数据库的key-val和清空所有数据库的key-val [flushdb flushall]
redis的五大数据类型是: String(字符串)、Hash(哈希)、 List(列表)、 Set 集合)和Zset (sorted set:有序集合)
1).基本介绍
string是redis的最基本的类型,一个 key对应一个value
string类型是二进制安全的,除[普]通的字符串外,也可以存放图片等数据
redis中字符串value 最大是 512M
举例:
存放一个地址信息:
address: 北京天安门
说明:
key: address
value: 北京天安门
string的crud
set[如果存在就相当于修改,不存在就是添加]]/get/del
2).string的使用细节
setex(set with expire)键,设置过期时间,单位:秒
1).基本介绍
hash是一个链值对集合,类似于go中的map:var user1 map[string]string
hash是一个string类型的 field 和 value的映射表,hash 特别适合用于存储对象
举例,存放一个User 信息:
user1 name "tom" age 30 job "go coder"
说明:
key: user1
uame "tom"和age 30 就是两对 filed-value
2).使用细节和注意事项
1).在给 user 设置name和 age 时,前面是一步一步设置,使用hmset 和 hmget 可以一次性来设置多个filed的值和返回多个filed的值
2).hlen 统计一个hash有几个元素
3).hexists key field 查看哈希表key中,给定域filed是否存在
1).基本介绍
列表是简单的字符串列表,按照插入顺序排序,可以添加一个元素到列表的头部(左边)或者尾部(右边)
list 本质是个链表,list的元素是有序的,元素的值可以重复
举例:
存放多个地址信息:
city 北京 天津 上海
说明:
key : city 北京 天津 上海 就是三个元素
2).crud
lpush/rpush/lrange/lpop/rpop/del
说明:
可以把list想象成一根管道
a.lindex,按照索引下标获得元素(从左到右,编号从0开始
b.llen key 返回列表key的长度,如果key不存在,则 key 被解释为一个空列表,返回 0
c.list的其它说明
- list数据,可以从左或者右插入添加
- 如果值全移除,对应的健也就消失了
1).基本介绍
redis的set 是string类型的无序集合
底层是 HashTable数据结构,set 也是存放很多字符串元素,字符串元素是无序的,而且元素的值不能重复
举例:存放多个邮件列表信息
email [email protected] [email protected]
说明:
key: email
[email protected] [email protected] 就是二个元素
redis > sadd email xx xxx
2).crud
sadd
smembers [取出所有值]
sismember [判断值是否是成员]
srem [删除指定值]
演示添加多个电子邮件信息的案例
说明:
golang 操作redis的客户端包有多个比如redigo、go-redis,github 上 Star 最多的莫属redigo
github地址:
https//github.com/garyburd/redigo
目前已经迁移到:
https://github.com/gomodule/redigo
文档:
https//godoc.org/github.com/garyburd/redigo/redis
命令:
go get github.com/garyburd/redigo/redis
文件中引入命令:
import "github.com/garyburd/redigo/redis"
安装
1).使用第三方开源的 redis 库: https//github.com/garyburd/redigo/redis
2).在使用redis前,先安装第三方 redis库,在 GOPATH 路径下执行安装指令:
D:goProject>go get github.com/garyburd/redigo/redis
3).装成功后,可以看到如下包
特别说明:在安装redis库前,确保己经安装并配置了 Git ,因为是从 github 下载安装 Redis 库的,如果没有安装配置过 Git ,请安装配置 Git
Conn接口是与Redis 协作的主要接口,可以使用Dial,DialWithTimeout或者NewConn函数来创建连接,当任务完成时,应用程序必须调用Close函数来完成操作
package main import( "github.com/garyburd/redigo/redis" "fmt" ) func main(){ //相关代码 conn, err = redis.Dial("tcp", "127.0.0.1:6379") if err != nil { fmt.Println("connect redis error", err) return } defer conn.Close() }
连接池
说明:
通过 Golang 对 Redis 操作,还可以通过 Redis 链接池,流程如下:
1).事先初始化一定数量的链接,放入到链接池
2).当go需要操作redis时,直接从redis链接池取出链接即可
3).这样可以节省临时获取redis链接的时间,从而提高效率
package main
import (
"fmt"
"github.com/garyburd/redigo/redis" //引入redis包
)
//定义一个全局变量
var pool *redis.Pool
//当启动程序时,就初始化连接池
func init() {
pool = &redis.Pool{
MaxIdle: 8, //最大空闲连接数
MaxActive: 0, //表示和数据库的最大连接数, 0 表示没有限制
IdleTimeout: 100, //最大空闲时间
Dial: func () (redis.Conn, error) { //初始化连接的代码, 连接协议,连接哪个ip
return redis.Dial("tcp", "127.0.0.1:6379")
},
}
}
func main() {
//从pool取出一个连接
conn := pool.Get()
defer conn.Close()
_, err := conn.Do("Set", "name", "wangwu")
if err != nil {
fmt.Printf("conn.do set err = %v\n", err)
return
}
//取出
res, err := conn.Do("Get", "name")
if err != nil {
fmt.Printf("conn.do get err = %v\n", err)
return
}
fmt.Printf("conn.do get result = %v\n", res)
//要从pool取出连接,一定要保证连接池是没有关闭的
}
通过使用Conn接口中的do方法执行redis命令,redis 命令大全参考:http://doc.redisfans.com/
go中发送与响应对应类型:
Do函数会必要时将参数转化为二进制字符串Go Type
redis命令响应会用以下go类型表示
可以使用go的类型断言或者 reply 辅助函数将返回的 interface { }转换为对应类型
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.Printf("redis Dial err = %v\n", err)
return
}
defer conn.Close() //延时conn
//2.通过go向redis写入数据string(key-value)
_, err = conn.Do("Set", "name", "张三")
if err != nil {
fmt.Printf("redis set err = %v\n", err)
return
}
//3.通过go向redis读取数据string(key-value)
res, err := redis.String(conn.Do("Get", "name"))
if err != nil {
fmt.Printf("redis set err = %v\n", err)
return
}
fmt.Printf("success %v\n", res)
}
_, err = conn.Do("expire", "name", 10) // 10秒过期
if err != nil {
fmt.Println("set expire error:", err)
return
}
//通过go向redis写入数据和读取数据
//1.连接redis
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Printf("redis Dial err = %v\n", err)
return
}
defer conn.Close() //延时conn
//批量获取mget,批量设置mset
_, err = conn.Do("MSet", "name", "张三", "age", 22)
if err != nil {
fmt.Printf("redis mset err = %v\n", err)
return
}
res, err := redis.String(conn.Do("MGet", "name", "age"))
if err != nil {
fmt.Printf("redis mset err = %v\n", err)
return
} else {
res_type := reflect.TypeOf(res)
fmt.Printf("res type : %s\n", res_type) // []string
fmt.Printf("mget name: %s\n", res) // "张三" 22
fmt.Println(len(res)) //2
}
//通过go向redis写入数据和读取数据
//1.连接redis
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Printf("redis Dial err = %v\n", err)
return
}
defer conn.Close() //延时conn
//list
_, err = conn.Do("LPush", "list1", "ele1", "ele2", "ele3")
if err != nil {
fmt.Printf("redis LPush err = %v\n", err)
return
}
res, err := redis.String(conn.Do("LPop", "list1"))
if err != nil {
fmt.Printf("redis LPop err = %v\n", err)
return
} else {
res_type := reflect.TypeOf(res)
fmt.Printf("res type : %s\n", res_type) // []string
fmt.Printf("mget name: %s\n", res) // ele3
}
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.Printf("redis Dial err = %v\n", err)
return
}
defer conn.Close() //延时conn
//hset方式单个写入
//2.通过go向redis写入数据hash
_, err = conn.Do("HSet", "user1", "name", "张三")
if err != nil {
fmt.Printf("redis hset err = %v\n", err)
return
}
_, err = conn.Do("HSet", "user1", "age", 22)
if err != nil {
fmt.Printf("redis hset err = %v\n", err)
return
}
//hget方式单个获取
//3.通过go向redis读取数据hash
resName, err := redis.String(conn.Do("HGet", "user1", "name"))
if err != nil {
fmt.Printf("redis hset err = %v\n", err)
return
}
resAge, err := redis.Int(conn.Do("HGet", "user1", "age"))
if err != nil {
fmt.Printf("redis hset err = %v\n", err)
return
}
fmt.Printf("success user1 name=%v, age=%v\n", resName, resAge)
//hmset批量方式多个写入
_, err = conn.Do("HMSet", "user2", "name", "李四", "age", 99)
if err != nil {
fmt.Printf("redis hmset err = %v\n", err)
return
}
//hmget批量方式多个获取
res, err := redis.Strings(conn.Do("HMGet", "user2", "name", "age"))
if err != nil {
fmt.Printf("redis hmset err = %v\n", err)
return
}
for i, v := range res {
fmt.Printf("res[%v] = %v\n", i, v)
}
}
要求:通过终端输入三个monster信息,使用go操作redis,存放到redis中[可以使用hash类型]
package main
import(
"fmt"
"strconv"
"github.com/garyburd/redigo/redis" //引入redis包
)
func main() {
//连接redis
conn, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
fmt.Printf("redis Dial err = %v\n", err)
return
}
defer conn.Close() //延时conn
//Monster信息:name,age, skill
//要求:通过终端输入三个monster信息,使用go操作redis,存放到redis中[可以使用hash类型]
//遍历所有monster信息,并显示到终端
for i := 1; i <= 3; i++ {
fmt.Printf("第%d个monster信息:\n", i)
var name string
var age int
var skill string
fmt.Printf("请输入第%d个monster的姓名:", i)
fmt.Scanln(&name)
fmt.Printf("请输入第%d个monster的年龄:", i)
fmt.Scanln(&age)
fmt.Printf("请输入第%d个monster的技能:", i)
fmt.Scanln(&skill)
//hmset方式批量写入
//通过go向redis写入数据hash
_, err = conn.Do("HMSet", "monster" + strconv.Itoa(i), "name", name, "age", age, "skill", skill)
if err != nil {
fmt.Printf("redis hmset err = %v\n", err)
return
}
}
//先获取所有keys
keys, err := redis.Strings(conn.Do("Keys", "monster*"))
if err != nil {
fmt.Printf("redis keys err = %v\n", err)
return
}
//遍历keys
for index, monster := range keys {
//hmget批量方式多个获取
res, err := redis.Strings(conn.Do("HMGet", monster, "name", "age", "skill"))
if err != nil {
fmt.Printf("redis hmGet err = %v\n", err)
return
}
//遍历单个monster 的hash
for i, v := range res {
fmt.Printf("第%d个monster结果: res[%v] = %v\n", index, i, v)
}
}
}
[上一节][go学习笔记.第十六章.TCP编程] 4.项目-海量用户即时通讯系统-显示在线用户列表,群聊
[下一节][go学习笔记.第十八章.数据结构] 1.基本介绍,稀疏数组,队列(数组实现),链表