Last active
December 16, 2016 06:57
-
-
Save tupunco/20f8928abfdf7bc2cd9f5f4381510953 to your computer and use it in GitHub Desktop.
boltdb demo
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"encoding/json" | |
"errors" | |
"reflect" | |
"github.com/boltdb/bolt" | |
"github.com/timshannon/bolthold" | |
) | |
// BoltDB WebUI 工具: | |
// cd ./data | |
// boltdbweb -d=db.bolt -p=9000 -s="G:/Work/GoPath/src/github.com/evnix/boltdbweb/" | |
const ( | |
boltDBFileName = "data/db.bolt" | |
) | |
var ( | |
//BoltX BoltDB Store | |
BoltX *BoltWrap | |
boltXModels = make(map[string]interface{}) // bolt models map | |
boltXHasInit bool // bolt models has int | |
) | |
func init() { | |
Registr2Bolt(&BoltIDIncrement{}) | |
} | |
// initBoltDB 初始化 BoltDB 配置 | |
func initBoltDB() { | |
BoltX = NewBoltWrap(boltDBFileName) | |
//INFO: bolthold 会为每个 typeOf(BoltModels) 创建一个 Bucket, | |
// 对每个 Model 初始化一下, 避免没有对某 Model 进行过 `写` 操作之前 Get 的时候报 bucket nil 错误. | |
for _, data := range boltXModels { | |
if err := BoltX.Upsert("-", data); err != nil { | |
panic(err) | |
} | |
} | |
} | |
// Registr2Bolt init Registr BoltDB Model | |
func Registr2Bolt(defaultData interface{}) { | |
boltXModels[reflect.TypeOf(defaultData).String()] = defaultData | |
} | |
// GetBoltStore get bolt store | |
func GetBoltStore(dbFileName string) (*bolthold.Store, error) { | |
if len(dbFileName) <= 0 { | |
return nil, errors.New("dbFileName param nil") | |
} | |
//return bolthold.Open(dbFileName, 0666, nil) | |
jsonOptions := &bolthold.Options{ | |
Encoder: DefaultEncode, | |
Decoder: DefaultDecode, | |
} | |
return bolthold.Open(dbFileName, 0666, jsonOptions) | |
} | |
//----------------------BoltWrap---------------------- | |
// BoltWrap bolt wrap | |
type BoltWrap struct { | |
*bolthold.Store | |
dbFileName string | |
} | |
// BoltIDIncrement ID Increment | |
type BoltIDIncrement struct { | |
Current int64 | |
} | |
// NewBoltWrap new BoltWrap | |
func NewBoltWrap(dbFileName string) *BoltWrap { | |
db, err := GetBoltStore(dbFileName) | |
if err != nil { | |
panic("init BoltDB fail") | |
} | |
return &BoltWrap{ | |
dbFileName: dbFileName, | |
Store: db, | |
} | |
} | |
// IsNotFoundError is error notFound | |
func (b *BoltWrap) IsNotFoundError(err error) bool { | |
return err == bolthold.ErrNotFound | |
} | |
// GeNextBoltID Ge Next BoltID | |
func (b *BoltWrap) GeNextBoltID(tx *bolt.Tx, key interface{}) (int64, error) { | |
if tx == nil || key == nil { | |
return -1, errors.New("tx or key param nil") | |
} | |
id := &BoltIDIncrement{} | |
err := b.TxGet(tx, key, id) | |
if err != nil && !b.IsNotFoundError(err) { | |
tx.Rollback() | |
return -1, err | |
} | |
if id.Current <= 0 { | |
id.Current = 1 | |
if err = b.TxUpsert(tx, key, id); err != nil { | |
tx.Rollback() | |
return -1, err | |
} | |
} else { | |
id.Current++ | |
if err = b.TxUpdate(tx, key, id); err != nil { | |
tx.Rollback() | |
return -1, err | |
} | |
} | |
return id.Current, nil | |
} | |
//-----------BoltDB JSON Encode/tDecode------------- | |
// DefaultEncode is the default encoding func for bolthold (Gob) | |
func DefaultEncode(value interface{}) ([]byte, error) { | |
var buff bytes.Buffer | |
en := json.NewEncoder(&buff) | |
err := en.Encode(value) | |
if err != nil { | |
return nil, err | |
} | |
return buff.Bytes(), nil | |
} | |
// DefaultDecode is the default decoding func for bolthold (Gob) | |
func DefaultDecode(data []byte, value interface{}) error { | |
var buff bytes.Buffer | |
de := json.NewDecoder(&buff) | |
_, err := buff.Write(data) | |
if err != nil { | |
return err | |
} | |
err = de.Decode(value) | |
if err != nil { | |
return err | |
} | |
return nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"strings" | |
) | |
// ErrDataNotExist 数据不存在 错误 | |
type ErrDataNotExist struct { | |
Data interface{} | |
Message string | |
} | |
// IsErrDataNotExist Check IS ErrDataNotExist | |
func IsErrDataNotExist(err error) bool { | |
_, ok := err.(*ErrDataNotExist) | |
return ok | |
} | |
//Error String | |
func (err *ErrDataNotExist) Error() string { | |
return fmt.Sprintf("Data-Not-Exist [Data: %+v, Message: %s]", err.Data, err.Message) | |
} | |
//---------------------------------- | |
// ErrParamsError 参数错误 | |
type ErrParamsError struct { | |
Params []string | |
} | |
// NewParamsError new ErrParamsError | |
func NewParamsError(params ...string) error { | |
return &ErrParamsError{ | |
Params: params, | |
} | |
} | |
// IsParamsError Check IS ErrParamsError | |
func IsParamsError(err error) bool { | |
_, ok := err.(*ErrParamsError) | |
return ok | |
} | |
//Error String | |
func (err *ErrParamsError) Error() string { | |
if len(err.Params) <= 0 { | |
return "param nil" | |
} | |
return fmt.Sprintf("params [%s] nil", strings.Join(err.Params, ",")) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "fmt" | |
func main() { | |
initBoltDB() | |
addUser, err := AddOrUpdateBoltUserInfo(&User{ | |
OpenID: "21111213-415126", | |
Nickname: "hell2112o", | |
}) | |
fmt.Printf("add:%+v-err:%+v\r\n", addUser, err) | |
addUser, err = GetUserByIDFromBolt(1) | |
fmt.Printf("get:%+v-err:%+v\r\n", addUser, err) | |
addUser, err = GetUserByIDFromBolt(2) | |
fmt.Printf("get:%+v-err:%+v\r\n", addUser, err) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"fmt" | |
"github.com/boltdb/bolt" | |
"github.com/timshannon/bolthold" | |
) | |
const ( | |
boltUserKey = "User_ID:%d" //user 表 key | |
boltUserIDIncrementKey = "User_ID_Increment" //user 表 ID 计数 | |
) | |
// User 用户基础数据表 | |
type User struct { | |
ID int64 `json:"id"` | |
OpenID string `json:"-" boltholdIndex:"OpenID"` // 用户的唯一标识 | |
Nickname string `json:"nickName"` // 用户昵称 | |
} | |
func init() { | |
Registr2Bolt(&User{}) | |
} | |
// GetUserByIDFromBolt GetUserByID returns the user object by given ID if exists. | |
func GetUserByIDFromBolt(id int64) (*User, error) { | |
if id <= 0 { | |
return nil, errors.New("userID nil") | |
} | |
u := new(User) | |
key := fmt.Sprintf(boltUserKey, id) | |
err := BoltX.Get(key, u) | |
if err != nil { | |
if BoltX.IsNotFoundError(err) { | |
return nil, &ErrDataNotExist{ | |
Data: &struct{ UserID int64 }{id}, | |
} | |
} | |
return nil, err | |
} | |
return u, nil | |
} | |
// GetUserByOpenIDFromBolt Get UserInfo By OpenID | |
func GetUserByOpenIDFromBolt(openID string) (*User, error) { | |
if len(openID) <= 0 { | |
return nil, errors.New("openID nil") | |
} | |
var result []*User | |
err := BoltX.Find(&result, bolthold.Where("OpenID").Eq(openID)) | |
if BoltX.IsNotFoundError(err) || len(result) <= 0 { | |
return nil, &ErrDataNotExist{ | |
Data: &struct{ OpenID string }{openID}, | |
} | |
} | |
if err != nil { | |
return nil, err | |
} | |
u := result[0] | |
return u, nil | |
} | |
// AddOrUpdateBoltUserInfo 添加或者更新用户 | |
func AddOrUpdateBoltUserInfo(u *User) (*User, error) { | |
if len(u.OpenID) <= 0 { | |
return nil, NewParamsError("OpenID") | |
} | |
var err error | |
var has bool | |
user := new(User) | |
user, err = GetUserByOpenIDFromBolt(u.OpenID) | |
if err != nil && !IsErrDataNotExist(err) { | |
return nil, err | |
} | |
if user != nil && user.ID > 0 { | |
has = true | |
} | |
bx := BoltX | |
var tx *bolt.Tx | |
if tx, err = bx.Bolt().Begin(true); err != nil { | |
return nil, err | |
} | |
if has { //更新用户资料 | |
key := fmt.Sprintf(boltUserKey, user.ID) | |
user.Nickname = u.Nickname | |
if err = bx.TxUpdate(tx, key, user); err != nil { | |
tx.Rollback() | |
return nil, err | |
} | |
} else { //添加新用户 | |
// 生成新的 UserID | |
var nextID int64 | |
if nextID, err = bx.GeNextBoltID(tx, boltUserIDIncrementKey); err != nil { | |
tx.Rollback() | |
return nil, err | |
} | |
key := fmt.Sprintf(boltUserKey, nextID) | |
user = &User{ | |
ID: nextID, | |
OpenID: u.OpenID, | |
Nickname: u.Nickname, | |
} | |
if err := bx.TxInsert(tx, key, user); err != nil { | |
tx.Rollback() | |
return nil, err | |
} | |
} | |
if err = tx.Commit(); err != nil { | |
return nil, err | |
} | |
return user, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment