NutsDB是纯Go语言编写一个简单、高性能、内嵌型、持久化的key-value数据库。

NutsDB支持事务,从v0.2.0之后的版本开始支持ACID的特性,支持多种数据结构,如列表(list)、集合(set)、有序集合(sorted set),允许使用配置自定义读写方式、启动载入、sync同步等。

GitHub: https://github.com/xujiajun/nutsdb

封装如下:

package db

import (
	"path/filepath"

	"github.com/xujiajun/nutsdb"
)

// Bucket 即 NutsDB 桶,表示一个文档项目名称
type Bucket = string

// DB 一个数据库连接结构
type DB struct {
	// subdir in rtfd.cfg base_dir
	DBDir string
	// instance of nutsdb
	obj *nutsdb.DB
}

// New 打开一个DB连接
func New(DBDir string) (db *DB, err error) {
	opt := nutsdb.DefaultOptions
	opt.Dir = DBDir
	connect, err := nutsdb.Open(opt)
	if err != nil {
		return
	}
	return &DB{DBDir, connect}, nil
}

// Close 关闭连接
func (db *DB) Close() error {
	err := db.obj.Close()
	if err != nil {
		return err
	}
	return nil
}

// Set 添加数据
func (db *DB) Set(name Bucket, key, value []byte) error {
	return db.ExpireSet(name, key, value, 0)
}

// ExpireSet 添加数据(使用过期时间)
func (db *DB) ExpireSet(name Bucket, key, value []byte, ttl uint32) error {
	if err := db.obj.Update(
		func(tx *nutsdb.Tx) error {
			if err := tx.Put(name, key, value, ttl); err != nil {
				return err
			}
			return nil
		}); err != nil {
		return err
	}
	return nil
}

// Get 获取数据
func (db *DB) Get(name Bucket, key []byte) (value []byte, err error) {
	if err = db.obj.View(
		func(tx *nutsdb.Tx) error {
			e, err := tx.Get(name, key)
			if err != nil {
				return err
			}
			value = e.Value
			return nil
		}); err != nil {
		return
	}
	return value, nil
}

// Has 判断 桶 中是否有Key(特指k/v类型)
func (db *DB) Has(name Bucket, key []byte) bool {
	_, err := db.Get(name, key)
	if err == nil {
		return true
	}
	return false
}

// Delete 删除Key(并不能删除其他数据类型)
func (db *DB) Delete(name Bucket, key []byte) error {
	if err := db.obj.Update(
		func(tx *nutsdb.Tx) error {
			if err := tx.Delete(name, key); err != nil {
				return err
			}
			return nil
		}); err != nil {
		return err
	}
	return nil
}

// RPush 从指定bucket里面的指定队列key的右边入队一个或者多个元素
func (db *DB) RPush(name Bucket, key []byte, items ...[]byte) error {
	if err := db.obj.Update(
		func(tx *nutsdb.Tx) error {
			return tx.RPush(name, key, items...)
		}); err != nil {
		return err
	}
	return nil
}

// LPop 从指定bucket里面的指定队列key的左边出队一个元素,删除并返回
func (db *DB) LPop(name Bucket, key []byte) (item []byte, err error) {
	if err = db.obj.Update(
		func(tx *nutsdb.Tx) error {
			data, err := tx.LPop(name, key)
			if err != nil {
				return err
			}
			item = data
			return nil
		}); err != nil {
		return
	}
	return item, nil
}

// RPop 从指定bucket里面的指定队列key的右边出队一个元素,删除并返回
func (db *DB) RPop(name Bucket, key []byte) (item []byte, err error) {
	if err = db.obj.Update(
		func(tx *nutsdb.Tx) error {
			data, err := tx.RPop(name, key)
			if err != nil {
				return err
			}
			item = data
			return nil
		}); err != nil {
		return
	}
	return item, nil
}

// LSize 返回指定bucket下指定key列表的size大小(即列表元素数量)
func (db *DB) LSize(name Bucket, key []byte) (length int, err error) {
	if err = db.obj.Update(
		func(tx *nutsdb.Tx) error {
			size, err := tx.LSize(name, key)
			if err != nil {
				return err
			}
			length = size
			return nil
		}); err != nil {
		return
	}
	return length, nil
}

// LRange 返回指定bucket里面的指定队列key列表里指定范围内的元素。
// start 和 end 偏移量都是基于0的下标,即list的第一个元素下标是0,依次递增;
// 偏移量也可以是负数,表示偏移量是从list尾部开始计数。
func (db *DB) LRange(name Bucket, key []byte, start, end int) (items [][]byte, err error) {
	err = db.obj.View(
		func(tx *nutsdb.Tx) error {
			data, err := tx.LRange(name, key, start, end)
			if err != nil {
				return err
			}
			items = data
			return nil
		})
	if err != nil {
		return
	}
	return items, nil
}

// SAdd 添加一个指定的member元素到指定bucket的里的指定集合key中。
func (db *DB) SAdd(name Bucket, key []byte, members ...[]byte) error {
	if err := db.obj.Update(
		func(tx *nutsdb.Tx) error {
			return tx.SAdd(name, key, members...)
		}); err != nil {
		return err
	}
	return nil
}

// SRem 在指定bucket里面移除指定的key集合中移除指定的一个或者多个元素。
func (db *DB) SRem(name Bucket, key []byte, members ...[]byte) error {
	if err := db.obj.Update(
		func(tx *nutsdb.Tx) error {
			if err := tx.SRem(name, key, members...); err != nil {
				return err
			}
			return nil
		}); err != nil {
		return err
	}
	return nil
}

// SHasKey 判断bucket是否有某个key(特指set数据类型),发生错误时即不存在
func (db *DB) SHasKey(name Bucket, key []byte) bool {
	hasKey := false
	if err := db.obj.View(
		func(tx *nutsdb.Tx) error {
			ok, err := tx.SHasKey(name, key)
			if err != nil {
				return err
			}
			hasKey = ok
			return nil
		}); err != nil {
		return false
	}
	return hasKey
}

// SIsMember 返回成员member是否是指定bucket的存指定key集合的成员。
func (db *DB) SIsMember(name Bucket, key, member []byte) bool {
	is := false
	if err := db.obj.View(
		func(tx *nutsdb.Tx) error {
			ok, err := tx.SIsMember(name, key, member)
			if err != nil {
				return err
			}
			is = ok
			return nil
		}); err != nil {
		return false
	}
	return is
}

// SMembers 返回指定bucket的指定key集合所有的元素。
func (db *DB) SMembers(name Bucket, key []byte) (members [][]byte, err error) {
	if err = db.obj.View(
		func(tx *nutsdb.Tx) error {
			items, err := tx.SMembers(name, key)
			if err != nil {
				return err
			}
			members = items
			return nil
		}); err != nil {
		return
	}
	return members, nil
}

// SCard 返回指定bucket的指定的集合key的基数 (集合元素的数量)。
func (db *DB) SCard(name Bucket, key []byte) (length int, err error) {
	if err = db.obj.View(
		func(tx *nutsdb.Tx) error {
			num, err := tx.SCard(name, key)
			if err != nil {
				return err
			}
			length = num
			return nil
		}); err != nil {
		return
	}
	return length, nil
}

// Pipeline 开启事务并执行命令
func (db *DB) Pipeline() (t *TranCommand, err error) {
	// 开启事务
	tx, err := db.obj.Begin(true)
	if err != nil {
		return
	}
	return &TranCommand{tx}, nil
}

// TranCommand 表示事务管道
type TranCommand struct {
	tx *nutsdb.Tx
}

// AutoRollback 管道执行发生错误时自动回滚事务
func (t *TranCommand) AutoRollback(err error) error {
	if err != nil {
		// 回滚事务
		t.tx.Rollback()
		return err
	}
	return nil
}

// Set 管道中的 Set
func (t *TranCommand) Set(name Bucket, key, value []byte) error {
	return t.ExpireSet(name, key, value, 0)
}

// ExpireSet 管道中的 ExpireSet
func (t *TranCommand) ExpireSet(name Bucket, key, value []byte, ttl uint32) error {
	return t.AutoRollback(t.tx.Put(name, key, value, ttl))
}

// Delete 管道中的 Delete
func (t *TranCommand) Delete(name Bucket, key []byte) error {
	return t.AutoRollback(t.tx.Delete(name, key))
}

// RPush 管道中的 RPush
func (t *TranCommand) RPush(name Bucket, key []byte, items ...[]byte) error {
	return t.AutoRollback(t.tx.RPush(name, key, items...))
}

// SAdd 管道中的 SAdd
func (t *TranCommand) SAdd(name Bucket, key []byte, members ...[]byte) error {
	return t.AutoRollback(t.tx.SAdd(name, key, members...))
}

// SRem 管道中的 SRem
func (t *TranCommand) SRem(name Bucket, key []byte, members ...[]byte) error {
	return t.AutoRollback(t.tx.SRem(name, key, members...))
}

// Execute 执行提交事务
func (t *TranCommand) Execute() error {
	if err := t.tx.Commit(); err != nil {
		t.tx.Rollback()
		return err
	}
	return nil
}

·End·