Golang使用LMDB

clawhub · · 1090 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

lmdb的相关简介可以看我的其他博客,这里记录go简单使用lmdb。我使用了https://github.com/bmatsuo/lmdb-go这个开源工具。
具体使用代码请参考我的github
https://github.com/ClawHub/go-study.git
直接上代码:

结构体

//lmdb客户端结构体  只创建一个lmdb环境,一个DB库
type lmdbCliet struct {
    Env *lmdb.Env
    DBI lmdb.DBI
}

获取lmdb客户端

/**
 * 获取lmdb客户端
 *size: sets the size of the environment memory map.
 *path: Open an environment handle path
 *name: dbi name
 */
func NewClient(size int64, path string, name string) *lmdbCliet {
    //获取lmdb环境
    env, err := lmdb.NewEnv()
    if err != nil {
        log.LmdbLogger.Error("获取lmdb环境失败", zap.Error(err))
    }

    //设置最大库数量
    err = env.SetMaxDBs(1)
    if err != nil {
        log.LmdbLogger.Error("设置最大库数量失败", zap.Int("maxDBs", 1), zap.Error(err))
    }
    //设置最大存储
    err = env.SetMapSize(size)
    if err != nil {
        log.LmdbLogger.Error("设置最大存储失败", zap.Int64("mapSize", size), zap.Error(err))
    }
    //环境打开,Open an environment handle
    //modo:UNIX权限,用于设置创建的文件和信号量。
    err = env.Open(path, 0, 0644)
    if err != nil {
        log.LmdbLogger.Error("环境打开失败", zap.String("path", path), zap.Error(err))
    }
    //ReaderCheck从reader lock表中清除陈旧的条目,并返回清除的条目数量。
    readers, err := env.ReaderCheck()
    if err != nil {
        log.LmdbLogger.Error("ReaderCheck失败", zap.Int("readers", readers), zap.Error(err))
    } else {
        log.LmdbLogger.Info("ReaderCheck", zap.Int("readers", readers))
    }
    //创建DBI
    var dbi lmdb.DBI
    err = env.Update(func(txn *lmdb.Txn) (err error) {
        //dbi, err = txn.CreateDBI("example")
        dbi, err = txn.CreateDBI(name)
        fmt.Println(err)
        return
    })
    if err != nil {
        log.LmdbLogger.Error("创建DBI失败", zap.String("dbName", name), zap.Error(err))
    }
    return &lmdbCliet{env, dbi}
}

关闭环境

//close
func (c *lmdbCliet) Close() {
    if c.Env != nil {
        err := c.Env.Close()
        if err != nil {
            log.LmdbLogger.Error("Close fail", zap.Error(err))
        }
    }
}

获取db状态

//stat
func (c *lmdbCliet) Stat() string {
    stat, err := c.Env.Stat()
    if err != nil {
        if err != nil {
            log.LmdbLogger.Error("Stat fail", zap.Error(err))
        }
        return "stat error"
    }
    //json解析
    bytes, err := json.Marshal(stat)
    if err != nil {
        log.LmdbLogger.Error("Stat json Marshal fail", zap.Error(err))
        return "json marshal error"
    }
    return string(bytes)
}

简单方法封装

get
//get
func (c *lmdbCliet) Get(key string) string {
    //默认值""
    var result string
    _ = c.Env.View(func(txn *lmdb.Txn) (err error) {
        v, err := txn.Get(c.DBI, []byte(key))
        if err != nil {
            if err != nil {
                log.LmdbLogger.Error("Get fail", zap.String("key", key), zap.Error(err))
            }
            return err
        }
        //获取成功
        result = string(v)
        return nil
    })
    return result
}
set
//set
func (c *lmdbCliet) Set(key, val string) bool {
    //默认false
    var result bool
    _ = c.Env.Update(func(txn *lmdb.Txn) error {
        err := txn.Put(c.DBI, []byte(key), []byte(val), 0)
        if err != nil {
            if err != nil {
                log.LmdbLogger.Error("Set fail", zap.String("key", key), zap.String("val", val), zap.Error(err))
            }
            return err
        }
        //插入成功
        result = true
        return nil

    })
    return result
}

del

//Del
func (c *lmdbCliet) Del(key string) bool {
    //默认false
    var result bool
    _ = c.Env.Update(func(txn *lmdb.Txn) error {
        err := txn.Del(c.DBI, []byte(key), nil)
        if err != nil {
            if err != nil {
                log.LmdbLogger.Error("Del fail", zap.String("key", key), zap.Error(err))
            }
            return err
        }
        //删除成功
        result = true
        return nil
    })
    return result

}
batch put
//batch put
func (c *lmdbCliet) BatchPut(keyValMap map[string]string, commitNum int) bool {
    //使用锁,因为采用了mdb_txn_begin
    runtime.LockOSThread()
    defer runtime.UnlockOSThread()
    //默认false
    var result bool
    //开始事务
    txn, err := (c.Env).BeginTxn(nil, 0)
    if err != nil {
        log.LmdbLogger.Error("BeginTxn fail", zap.Error(err))
        return result
    }
    //打开游标
    var cur *lmdb.Cursor
    cur, err = txn.OpenCursor(c.DBI)
    if err != nil {
        log.LmdbLogger.Error("OpenCursor fail", zap.Error(err))
        return result
    }

    //入游标数量
    var num = 1
    //迭代待处理数据
    for key, val := range keyValMap {
        //入游标
        err = cur.Put([]byte(key), []byte(val), 0)
        if err != nil {
            log.LmdbLogger.Error("cur.Put fail", zap.String("key", key), zap.String("val", val), zap.Error(err))
            return result
        }
        //达到提交数量
        if num%commitNum == 0 {
            //提交事务
            err = txn.Commit()
            if err != nil {
                log.LmdbLogger.Error("txn.Commit() fail", zap.Error(err))
                return result
            }
            //新开启事务
            txn, err := (c.Env).BeginTxn(nil, 0)
            if err != nil {
                log.LmdbLogger.Error("BeginTxn fail", zap.Error(err))
                return result
            }
            //新开游标
            cur, err = txn.OpenCursor(c.DBI)
            if err != nil {
                log.LmdbLogger.Error("OpenCursor fail", zap.Error(err))
                return result
            }
        }

        //入游标数量+1
        num++
    }

    //最后提交一次事务
    //提交事务
    err = txn.Commit()
    if err != nil {
        log.LmdbLogger.Error("txn.Commit() fail", zap.Error(err))
        return result
    }
    return true
}

测试

func Demo() {
    log.LmdbLogger.Info("------lmdb---------")
    size := int64(102400)
    path := "F:\\lmdb"
    name := "db"
    client := NewClient(size, path, name)
    flag := client.Set("sex", "nan")
    log.LmdbLogger.Info("Set", zap.Bool("flag", flag))
    sex := client.Get("sex")
    log.LmdbLogger.Info(sex)
    log.LmdbLogger.Info(client.Stat())
}

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:clawhub

查看原文:Golang使用LMDB

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1090 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传