`
dalan_123
  • 浏览: 87404 次
  • 性别: Icon_minigender_1
  • 来自: 郑州
社区版块
存档分类
最新评论

beego源码cache

阅读更多
一、缓存
cache模块是一个go缓存管理器,目前能够支持多种缓存方式: Memory、File、Redis、Memcached等多种缓存适配模式,整体的设计想法参考'database/sql',
二、如何使用
go get -u github.com/astaxie/beego/cache

三、代码使用
1、首先要导入cache
import (
"github.com/astaxie/beego/cache"
)
2、初始化Cache
// 初始化一个内存缓存器并提供 60s进行缓存key有效检查
bm, err := cache.NewCache("memory", {"interval":60})
使用方式:
bm.Put("astaxie", 1, 10 * time.Second)  // 添加
bm.Get("astaxie")                                   // 获取
bm.IsExist("astaxie")                              // 存在
bm.Delete("astaxie")                               // 删除

注意:若是使用redis、memcached两种缓存方式需要引入对应的内容
go get -u github.com/astaxie/beego/cache/memcache   // 获取memcache
go get -u github.com/gomodule/redigo/redis                   // 获取redis
在使用的地方引入:
import _ "github.com/astaxie/beego/cache/memcache"
import _ github.com/gomodule/redigo/redis

四、引擎设置
1.Memory引擎
配置项:
{"interval":60}
指定gc检查的时间,定时检查cache中每个item是否有效
2.Memcache引擎
Memcache引擎使用的是gomemcache.
配置项:{"key":"collectionName","conn":":6039","dbNum":"0","password":"thePassWord"}
key: Redis collection 的名称
conn: Redis 连接信息
dbNum: 连接 Redis 时的 DB 编号. 默认是0.
password: 用于连接有密码的 Redis 服务器.
3.Redis引擎
Redis引擎使用redigo.
配置项:
{"conn":":6039"}
4.file
配置项
{"CachePath":"./cache","FileSuffix":".cache","DirectoryLevel":2,"EmbedExpiry":120}
CachePath 表示缓存的文件目录,
FileSuffix 表示文件后缀,
DirectoryLevel 表示目录层级,
EmbedExpiry 表示过期设置
五、自定义cache引擎
cache 模块采用了接口的方式实现,因此用户可以很方便的实现接口,然后注册就可以实现自己的 Cache 引擎:
type Cache interface {
    Get(key string) interface{}
    GetMulti(keys []string) []interface{}
    Put(key string, val interface{}, timeout time.Duration) error
    Delete(key string) error
    Incr(key string) error
    Decr(key string) error
    IsExist(key string) bool
    ClearAll() error
    StartAndGC(config string) error
}

用户开发完需要进行如下的操作: 将自定义的cache引擎注入到本地缓存中心:adapters对应的map中
func init() {
Register("newcache", NewDefineCache())
}
补充
1、redis对应的缓存包使用
import (
    "fmt"
    "github.com/gomodule/redigo/redis"
    "log"
    "time"
)

const (
    REDIS_SERVER = "127.0.0.1"
    REDIS_PORT   = 6379
    DEFAULT_KEY  = "beecacheRedis"
)

type RedisPool struct {
    p        *redis.Pool
    conninfo string
    password string
    maxIdle  int
    dbNum    int
}

func NewRedisCache() RedisPool {
    return RedisPool{}
}

func (rc *RedisPool) InitRedisPool() {
    rc.conninfo = fmt.Sprintf("%s:%d", REDIS_SERVER, REDIS_PORT)

    dialFunc := func() (conn redis.Conn, err error) {
        conn, err = redis.Dial("tcp", rc.conninfo)
        if err != nil {
            return nil, err
        }

        // password
        if rc.password != "" {
            if _, err = conn.Do("AUTH", rc.password); err != nil {
                conn.Close()
                return nil, err
            }
        }

        _, selecterr := conn.Do("SELECT", rc.dbNum)
        if selecterr != nil {
            conn.Close()
            return nil, err
        }
        return
    }

    rc.p = &redis.Pool{
        MaxIdle:     100,
        IdleTimeout: 180 * time.Second,
        Dial:        dialFunc,
    }
}

func Associate(originKey interface{}) string {
    return fmt.Sprintf("%s:%s", DEFAULT_KEY, originKey)
}

func main() {
    redisPool := NewRedisCache()
    redisPool.InitRedisPool()

    conn := redisPool.p.Get()
    defer conn.Close()

    resp, err := conn.Do("SET", Associate("hello"), "world")
    if err != nil {
        panic(err)
    }
    fmt.Println(resp)

    resp, err = conn.Do("GET", Associate("hello"))
    if err != nil {
        panic(err)
    }
    //sresp , err := redis.Values(resp, err)
    fmt.Println(redis.String(resp,err))

    // add
    for i:=0; i<1000; i++{
        key := fmt.Sprintf("hello_%d",i)
        value := fmt.Sprintf("world_%d", i)
        _, err = conn.Do("SET", Associate(key),value)
        if err != nil{
            log.Println(err)
        }
    }

    fmt.Println(redis.String(conn.Do("GET",Associate("hello_1"))))

    var keys []interface{}
    for i:=0; i < 50; i++{
        key := fmt.Sprintf("hello_%d",i)
        keys = append(keys, Associate(key))
    }

    fmt.Println(keys)

    resp, err = conn.Do("MGET",[]interface{}{Associate("hello_1"),Associate("hello_2"),Associate("hello_3")}... )
    fmt.Println(redis.Strings(resp, err))

    resp, err = conn.Do("MGET",keys...)  // 注意:mget指定key集合需要使用interface{}类型
    if err != nil{
        panic(err)
    }
    fmt.Println(redis.Strings(resp,err))

    ckeys, err := redis.Strings(conn.Do("KEYS",Associate("*")))
    fmt.Println(ckeys)
    for _, key := range ckeys{
        if _, err := conn.Do("DEL", (key)); err != nil{
            log.Println(err)
        }
    }

    fmt.Println(redis.String(conn.Do("GET",Associate("hello_999"))))
}

2、ssdb缓存包的使用
import (
    "fmt"
    "github.com/ssdb/gossdb/ssdb"
    "log"
    "math/rand"
    "time"
)

func main() {
    client, err := ssdb.Connect("127.0.0.1", 8888)
    if err != nil {
        panic(err)
    }

    resp, err := client.Do("set", "hello", "world")
    if err != nil {
        panic(err)
    }
    fmt.Println(resp)
    // setx指令 ttl单位:s
    resp, err = client.Do("setx", "hello1", "world1", int(2000*time.Millisecond/time.Second))
    if err != nil {
        panic(err)
    }
    fmt.Println(resp)

    resp, err = client.Do("get", "hello")
    if err != nil {
        panic(err)
    }
    fmt.Println(resp)

    //time.Sleep(2 * time.Second)
    resp, err = client.Do("get", "hello1")
    if err != nil {
        panic(err)
    }
    fmt.Println(resp)

    for i := 0; i < 1000; i++ {
        resp, err = client.Do("set", fmt.Sprintf("hello%d", i), fmt.Sprintf("world%d", i))
        if err != nil {
            panic(err)
        }
    }

    var keys []string
    for i := 0; i < 50; i++ {
        keys = append(keys, fmt.Sprintf("hello%d", i))
    }
    keys = append(keys, "hello10001")
    resp, err = client.Do("multi_get", keys)
    if err != nil {
        panic(err)
    }
    fmt.Println(resp)

    var values []interface{}
    if err == nil {
        for i := 1; i < len(resp); i += 2 {
            values = append(values, resp[i+1])
        }
    }
    fmt.Println(values)

    resp, err = client.Do("get", "hello1")
    if err != nil {
        panic(err)
    }
    fmt.Println(resp)

    // =============删除==============
    keyStart, keyEnd, limit := "", "", 50
    resp, err = client.Do("scan", keyStart, keyEnd, limit)

    fmt.Println(resp)

    for err == nil {
        size := len(resp)
        if size == 1 {
            log.Println("not delete items")
            break
        }
        keys := []string{}
        for i := 1; i < size; i += 2 {
            keys = append(keys, resp[i])
        }
        _, e := client.Do("multi_del", keys)
        if e != nil {
            panic(e)
        }
        if size > 2 {
            keyStart = resp[size-2]
        }
        resp, err = client.Do("scan", keyStart, keyEnd, limit)
    }

    resp, err = client.Do("get", fmt.Sprintf("hello%d", rand.Intn(999)))
    if err != nil {
        panic(err)
    }
    fmt.Println(resp)

    client.Do("incr", "counter", 1)
    client.Do("incr", "counter", 1)
    client.Do("incr", "counter", 1)
    fmt.Println(client.Do("get", "counter"))
}

以上提供了两个直接使用对应的原始包示例,便于熟悉对应的beego中cache模块的内容
六、 源码
基本上其他实现方式 大体差异不是很大,故在此罗列ssdb的源码
package ssdb
import (
    "encoding/json"
    "errors"
    "strconv"
    "strings"
    "time"
    "github.com/ssdb/gossdb/ssdb"
    "github.com/astaxie/beego/cache"
)

// 基于SSDB实现的缓存
// Cache SSDB adapter
type Cache struct {
    conn     *ssdb.Client   // ssdb实例
    conninfo []string       // ssdb链接信息
}

//NewSsdbCache create new ssdb adapter.
func NewSsdbCache() cache.Cache {   // 新建缓存
    return &Cache{}
}

// 获取指定缓存key的内容
// Get get value from memcache.
func (rc *Cache) Get(key string) interface{} {
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {  // 初始化ssdb链接
            return nil
        }
    }
    value, err := rc.conn.Get(key)   // 执行查询
    if err == nil {
        return value
    }
    return nil
}

// 查询多个缓存key的内容
// GetMulti get value from memcache.
func (rc *Cache) GetMulti(keys []string) []interface{} {
    size := len(keys)
    var values []interface{}
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {  // 初始化ssdb的链接
            for i := 0; i < size; i++ {           // 记录异常串
                values = append(values, err)
            }
            return values
        }
    }
    res, err := rc.conn.Do("multi_get", keys)  // 执行get
    resSize := len(res)
    if err == nil {
        for i := 1; i < resSize; i += 2 {  //[ok key value key value key value] 响应结果格式
            values = append(values, res[i+1])
        }
        return values
    }
    for i := 0; i < size; i++ {
        values = append(values, err)
    }
    return values
}

// 删除多个key
// DelMulti get value from memcache.
func (rc *Cache) DelMulti(keys []string) error {
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {
            return err
        }
    }
    _, err := rc.conn.Do("multi_del", keys)  // 执行删除
    return err
}

// 添加key到缓存并指定有效期
// 注意:目前只支持缓存值类型为string
// Put put value to memcache. only support string.
func (rc *Cache) Put(key string, value interface{}, timeout time.Duration) error {
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {
            return err
        }
    }
    v, ok := value.(string)   // 需要保证提供的缓存值类型=string 否则会抛出error("value must string")
    if !ok {
        return errors.New("value must string")
    }
    var resp []string
    var err error
    ttl := int(timeout / time.Second)  // 单位秒
    if ttl < 0 {               // 有效期<0 则对应的key一直有效
        resp, err = rc.conn.Do("set", key, v)
    } else {                   // 设置缓冲key及其有效期
        resp, err = rc.conn.Do("setx", key, v, ttl)
    }
    if err != nil {
        return err
    }
    if len(resp) == 2 && resp[0] == "ok" {  // 解析response
        return nil
    }
    return errors.New("bad response")
}

// 删除缓存key
// Delete delete value in memcache.
func (rc *Cache) Delete(key string) error {
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {
            return err
        }
    }
    _, err := rc.conn.Del(key)
    return err
}

// 增加缓存key计数
// Incr increase counter.
func (rc *Cache) Incr(key string) error {
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {
            return err
        }
    }
    _, err := rc.conn.Do("incr", key, 1)
    return err
}

// 减少缓存key计数
// Decr decrease counter.
func (rc *Cache) Decr(key string) error {
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {
            return err
        }
    }
    _, err := rc.conn.Do("incr", key, -1)
    return err
}

// 检查缓存key是否存在
// IsExist check value exists in memcache.
func (rc *Cache) IsExist(key string) bool {
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {
            return false
        }
    }
    resp, err := rc.conn.Do("exists", key)
    if err != nil {
        return false
    }
    if len(resp) == 2 && resp[1] == "1" {   // 响应格式:[ok 1]
        return true
    }
    return false

}

// 清空缓存内容
// ClearAll clear all cached in memcache.
func (rc *Cache) ClearAll() error {
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {
            return err
        }
    }
    keyStart, keyEnd, limit := "", "", 50
    resp, err := rc.Scan(keyStart, keyEnd, limit)
    for err == nil {    // 指定删除缓存key范围=50  防止过大影响ssdb
        size := len(resp)
        if size == 1 {
            return nil
        }
        keys := []string{}
        for i := 1; i < size; i += 2 {
            keys = append(keys, resp[i])
        }
        _, e := rc.conn.Do("multi_del", keys)
        if e != nil {
            return e
        }
        keyStart = resp[size-2]
        resp, err = rc.Scan(keyStart, keyEnd, limit)
    }
    return err
}

// 扫描指定范围的缓存key 且指定限定个数 防止对应的key量过大 导致ssdb出现问题
// Scan key all cached in ssdb.
func (rc *Cache) Scan(keyStart string, keyEnd string, limit int) ([]string, error) {
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {
            return nil, err
        }
    }
    resp, err := rc.conn.Do("scan", keyStart, keyEnd, limit)  // 执行scan操作
    if err != nil {
        return nil, err
    }
    return resp, nil
}

// 启动缓存服务并执行定期GC
// StartAndGC start memcache adapter.
// config string is like {"conn":"connection info"}.
// if connecting error, return.
func (rc *Cache) StartAndGC(config string) error {
    var cf map[string]string
    json.Unmarshal([]byte(config), &cf)
    if _, ok := cf["conn"]; !ok {  // 指定ssdb链接字符串: ip:port
        return errors.New("config has no conn key")
    }
    rc.conninfo = strings.Split(cf["conn"], ";")
    if rc.conn == nil {
        if err := rc.connectInit(); err != nil {
            return err
        }
    }
    return nil
}

// 链接初始化 并持有
// connect to memcache and keep the connection.
func (rc *Cache) connectInit() error {
    conninfoArray := strings.Split(rc.conninfo[0], ":")
    host := conninfoArray[0]
    port, e := strconv.Atoi(conninfoArray[1])
    if e != nil {
        return e
    }
    var err error
    rc.conn, err = ssdb.Connect(host, port)
    return err
}

func init() {
    cache.Register("ssdb", NewSsdbCache)
}


         
       
分享到:
评论

相关推荐

    GO语言基于Golang+beego的数据查询系统源码.zip

    GO语言基于Golang+beego的数据查询系统源码程序以Excel表格方式导入数据,可自定义登陆账户验证列,以及相关联的登陆密码验证列,程序上传Excel之后会对数据源进行加密,并且屏蔽外网对数据源目录访问。 可能会需要...

    simple-cache(文档+JAR+JAR源码)

    simple-cache(文档+JAR+JAR源码)simple-cache(文档+JAR+JAR源码)simple-cache(文档+JAR+JAR源码)simple-cache(文档+JAR+JAR源码)simple-cache(文档+JAR+JAR源码)simple-cache(文档+JAR+JAR源码)simple-cache(文档+...

    PrimoCache 2.2.0继续试用e源码+批处理 官方中文服务器版和桌面版永久使用

    PrimoCache是一款高效的数据缓存软件,主要用于提升硬盘或固态驱动器的读写性能,尤其对于机械硬盘来说,效果尤为显著。它的工作原理是通过将频繁访问的数据存储在高速缓存设备(如SSD)中,从而减少对低速存储设备...

    基于Vue与Beego的ido桌面工具设计源码

    该项目是一款基于Vue与Beego框架构建的ido桌面工具源码,包含170个文件,涵盖60个Vue组件、40个JavaScript脚本、22个SVG图形、19个PNG图像、7个GIF动画、6个MP3音频、4个JPG图片、3个JSON配置文件,以及babelrc和...

    (基于vue.js element框架+golang beego框架开发)是一个基于运维场景设计的企业级运维发布系统

    gopub(基于vue.js element框架+golang beego框架开发)是一个基于运维场景设计的企业级运维发布系统。配置简单、功能完善、界面流畅、开箱即用!支持git、jenkins版本管理,支持各种web代码发布,一键完成Golang,...

    Beego中文文档PDF

    Beego是一个使用Go语言开发的开源框架,它旨在以Go语言的思维帮助开发者构建并开发Web应用程序。...文档还提供了源码的链接,并建议初学者先阅读快速入门部分,如果有需要,可以通过搜索邮件列表或者提问来获得帮助。

    Cache测试apk源码

    "Cache测试apk源码"是一个专门用于测试Android设备上可用缓存空间的应用,通过不断占用内存和缓存直至系统强制关闭,从而得知设备的缓存容量。 首先,我们要理解Android中的缓存类型。Android主要使用两种类型的...

    opencv-4.6.0-cache.zip

    这个是windows上源码编译opencv4.6.0+opencv-contrib4.6.0时候cmake时候缓存文件,只需要将压缩文件夹解压到opencv源码目录下面,cmake-gui上configure时候就不会报错,注意解压后文件夹名字是.cache,文件夹名字不能...

    SpringBoot-Cache源码分享.zip

    SpringBoot与缓存原理,整合redis、redis序列化,缓存注解、运行流程、原理讲解 配套三篇文章,推荐大家哦 https://blog.csdn.net/xiaozhegaa/article/details/110084902

    cache实验 cache实验 cache实验

    cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验cache实验...

    基于Beego框架开发的航班数据可视化项目源码(课程设计)+运行截图.zip

    基于Beego框架开发的航班数据可视化项目源码(课程设计)+运行截图.zip基于Beego框架开发的航班数据可视化项目源码(课程设计)+运行截图.zip基于Beego框架开发的航班数据可视化项目源码(课程设计)+运行截图.zip基于...

    beego-develop.zip

    "beego-develop"可能是一个开发目录,其中可能包含了Beego框架的核心源码、示例项目、开发工具或者特定的扩展模块。 在这个目录下,我们可以期待找到以下内容: 1. `main.go`:项目的入口文件,通常会包含初始化...

    opencv-4.5.4-cache.zip

    这个是windows上源码编译opencv4.5.4+opencv-contrib4.5.4时候cmake时候缓存文件,只需要将压缩文件夹解压到opencv源码目录下面即可,cmake-gui上configure时候就不会报错,注意解压后文件夹名字是.cache,文件夹名字...

    SSCOM源码 DELPHI 源码

    SSCOM源码 DELPHI 源码 绝对源码!欢迎下载

    opencv-4.8.0-cache.zip

    这个是windows上源码编译opencv4.8.0+opencv-contrib4.8.0时候cmake时候缓存文件,只需要将压缩文件夹解压到源码目录下面,cmake-gui上configure时候就不会报错,注意解压后文件夹名字是.cache,文件夹名字不能改变,...

    beego 环境安装(windows 和 contos)

    ### Beego环境安装详解(Windows 和 CentOS) #### 一、Beego简介 Beego 是一个用 Go 语言编写的高性能 Web 框架,适用于快速开发 RESTful 风格的应用程序。它提供了丰富的功能,如自动代码生成、内置模板引擎、...

    Golang实现的基于beego框架的接口在线文档管理系统源码.zip

    这是一个基于Golang编程语言和Beego框架开发的接口在线文档管理系统源码项目,名为"Mindoc"。在本文中,我们将深入探讨这个系统的实现细节、技术栈以及如何使用和理解Beego框架。 Golang,也被称为Go语言,是Google...

    应用源码之-Image-Cache-master.zip

    《Android应用源码解析——Image-Cache-master》 在Android开发中,图片缓存机制是不可或缺的一部分,尤其是在处理大量图片的场景下,如新闻资讯、电商应用等。本篇文章将深入探讨Image-Cache-master这个开源项目,...

    在ASP.NET 2.0中操作数据:使用SQL Cache Dependencies(源码)

    ASP.NET 2.0是一个强大的Web应用程序开发框架,由微软公司推出,用于构建动态网站、Web应用程序和服务。...在ASPNET_Data_Tutorial_61_CS这个源码文件中,你将找到具体的实现示例,帮助你更好地理解和应用这一技术。

    Memory Systems - Cache_SRAM_ddrmemorycache_memory_源码.zip

    在这个"Memory Systems - Cache_SRAM_ddrmemorycache_memory_源码"的压缩包中,我们很可能会找到关于这些技术的源代码实现,这对于理解其工作原理和优化内存管理非常有帮助。 首先,让我们深入了解一下Cache。Cache...

Global site tag (gtag.js) - Google Analytics