Golang操作Redis

Golang操作Redis

安装第三方开源Redis库

Golang操作Redis

Golang操作Redis

注意 : 命令行操作不成功的直接去这个github网站里下载压缩包解压到指定目录即可

1. 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)
}

2. 操作Hash

说明:通过Golang对Redis操作 Hash数据类型

对hash数据结构,field-val 是一个一个放入和读取:

package main
import (
    "fmt"
	"github.com/garyburd/redigo/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("HSet", "user01", "name", "john")
	if err != nil {
		fmt.Println("hset err = ", err)
		return
	}

	_, err := conn.Do("HSet", "user01", "age", 18)
	if err != nil {
		fmt.Println("hset err = ", err)
		return
	}

	// 3.通过go向redis读取数据
	r1, err :=redis.String(conn.Do("HGet", "user01", name))
	if err != nil {
		fmt.Println("hget err = ", err)
		return
	}

	r2, err := redis.Do("HGet", "user01", "age")
	if err != nil {
		fmt.Println("hget err = ", err)
		return 
	}

	// 返回的r 是innterface{}
	// 因为name对应的值是string,因此我们需要转换
	// nameString := r.(string)

	fmt.Printf("操作 OK r1 = %v r2 = %v\n", r1, r2)
}

对hash数据结构,field-val是 批量放入和读取:

package main
import (
    "fmt"
	"github.com/garyburd/redigo/redis"
)

func main() {
	conn, err := redis.Dial("tcp", "127.0.0.1:6397")
	if err != nil {
		fmt.Println("redis Dial err = ", err)
		return
	}

	_, err := conn.Do("HMSet", "user02", "name", "jack", "age", 21)
	if err != nil {
		fmt.Println("HMSet err = ", err)
		return
	}

	r, err := redis.String(conn.Do("HMGet", "user02", "name", "age"))
	if err != nil {
		fmt.Println("hmget err = ", err)
		return
	}

	for i, V := range r {
		fmt.Printf("r[%d] = %s\n", i, v)
	}
}

3. 批量Set/Get数据

说明:通过golang对redis操作,一次操作可以Set/Get多个key-val数据

_, err := conn.Do("MSet", "name", "golang", "address", "北京")
r, err := redis.String(conn.Do("MGet", "name", "address"))

for _, v := range r {
    fmt.Println(v)
}
3.1 给数据设置有效时间

说明:通过golang对redis操作,给 key-val设置有效时间

// 给name数据设置有效时间为10s
_, err = conn.Do("expire", "name", 10)

4. 操作List

说明: 通过golang对redis操作List数据类型

_, err := conn.Do("lpush", "heroList", "no1:悟空", 30, "no2:八戒", 33)
r, err := redis.String(conn.Do("rpop", "heroList"))

5. Redis 链接池

说明:通过Golang对Redis操作,还可以通过Redis链接池,步骤:

1)事先初始化一定数量的链接,放入到链接池

2)当Go需要操作Redis时,直接从Redis链接池取出链接即可

3)这样 可以节省临时获取Redis链接的时间,从而提高效率

4)示意图:

Golang操作Redis

5 ) 链接池使用案例:

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)
}

注意:redis.Poll 结构介绍:

// github.com/garyburd/redigo/redis/pool.go
type Pool struct {

    // Dial()方法返回一个连接,从在需要创建连接到的时候调用
    Dial func() (Conn, error)

    // TestOnBorrow()方法是一个可选项,该方法用来诊断一个连接的健康状态
    TestOnBorrow func(c Conn, t time.Time) error

    // 最大空闲连接数
    MaxIdle int

    // 一个pool所能分配的最大的连接数目
    // 当设置成0的时候,该pool连接数没有限制
    MaxActive int

    // 空闲连接超时时间,超过超时时间的空闲连接会被关闭。
    // 如果设置成0,空闲连接将不会被关闭
    // 应该设置一个比redis服务端超时时间更短的时间
    IdleTimeout time.Duration

    // 如果Wait被设置成true,则Get()方法将会阻塞
    Wait bool

    // mu protects fields defined below.
    mu     sync.Mutex
    cond   *sync.Cond
    closed bool
    active int

    // 空闲连接队列
    idle list.List
}

主要参数:

MaxIdle

  • 表示连接池空闲连接列表的长度限制
  • 空闲列表是一个栈式的结构,先进后出

MaxActive

  • 表示连接池中最大连接数限制
  • 主要考虑到服务端支持的连接数上限,以及应用之间”瓜分”连接数

IdleTimeout

  • 空闲连接的超时设置,一旦超时,将会从空闲列表中摘除
  • 该超时时间时间应该小于服务端的连接超时设置

区分两种使用场景:

  • 高频调用的场景,需要尽量压榨redis的性能:

    • 调高MaxIdle的大小,该数目小于maxActive,由于作为一个缓冲区一样的存在,扩大缓冲区自然没有问题
    • 调高MaxActive,考虑到服务端的支持上限,尽量调高
    • IdleTimeout由于是高频使用场景,设置短一点也无所谓,需要注意的一点是MaxIdle设置的长了,队列中的过期连接可能会增多,这个时候IdleTimeout也要相应变化
  • 低频调用的场景,调用量远未达到redis的负载,稳定性为重:

    • MaxIdle可以设置的小一些
    • IdleTimeout相应地设置小一些
      时间时间应该小于服务端的连接超时设置

区分两种使用场景:

  • 高频调用的场景,需要尽量压榨redis的性能:

    • 调高MaxIdle的大小,该数目小于maxActive,由于作为一个缓冲区一样的存在,扩大缓冲区自然没有问题
    • 调高MaxActive,考虑到服务端的支持上限,尽量调高
    • IdleTimeout由于是高频使用场景,设置短一点也无所谓,需要注意的一点是MaxIdle设置的长了,队列中的过期连接可能会增多,这个时候IdleTimeout也要相应变化
  • 低频调用的场景,调用量远未达到redis的负载,稳定性为重:

    • MaxIdle可以设置的小一些
    • IdleTimeout相应地设置小一些
    • MaxActive随意,够用就好,容易检测到异常
上一篇:Python 项目


下一篇:FastAPI(六十六)实战开发《在线课程学习系统》接口开发--用户注册接口开发