Boltdb是一个纯Go语言实现的键值数据存储库。

huangapple go评论82阅读模式
英文:

Boltdb-key-Value Data Store purely in Go

问题

Bolt在数据文件上获取文件锁,以防止多个进程同时打开同一个数据库。如果打开一个已经打开的Bolt数据库,它将会挂起,直到其他进程关闭它。

由于这种情况,是否存在连接池的概念,即多个客户端同时连接和访问数据库?在boltdb中是否可能实现这一点?比如,有多个连接同时读写数据库。如何实现这个功能?

英文:

Bolt obtains a file lock on the data file so multiple processes cannot open the same database at the same time. Opening an already open Bolt database will cause it to hang until the other process closes it.

As this is the case,is there any connection pooling concept like various clients connecting and accessing the database at the same time.? Is this possible in boltdb?Like there are various connections reading and writing in the database at the same time.How it can be implemented?

答案1

得分: 10

Bolt数据库通常嵌入到一个较大的程序中,不像共享数据库那样通过网络使用(类似于SQLite和MySQL的区别)。使用Bolt有点像拥有一个持久的map[[]byte][]byte,如果可能的话。根据你的需求,你可能只想使用类似Redis的东西。

话虽如此,如果你需要以这种方式使用Bolt,将其包装成一个简单的服务器并不是很困难。下面是一个示例,演示了如何通过HTTP从Bolt数据库中读写键。你可以使用Keep-Alive来进行连接池管理。

代码链接:https://github.com/skyec/boltdb-server

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/boltdb/bolt"
	"github.com/gorilla/mux"
)

type server struct {
	db *bolt.DB
}

func newServer(filename string) (s *server, err error) {
	s = &server{}
	s.db, err = bolt.Open(filename, 0600, &bolt.Options{Timeout: 1 * time.Second})
	return
}

func (s *server) Put(bucket, key, contentType string, val []byte) error {
	return s.db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte(bucket))
		if err != nil {
			return err
		}
		if err = b.Put([]byte(key), val); err != nil {
			return err
		}
		return b.Put([]byte(fmt.Sprintf("%s-ContentType", key)), []byte(contentType))
	})
}

func (s *server) Get(bucket, key string) (ct string, data []byte, err error) {
	s.db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(bucket))
		r := b.Get([]byte(key))
		if r != nil {
			data = make([]byte, len(r))
			copy(data, r)
		}

		r = b.Get([]byte(fmt.Sprintf("%s-ContentType", key)))
		ct = string(r)
		return nil
	})
	return
}

func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)

	if vars["bucket"] == "" || vars["key"] == "" {
		http.Error(w, "Missing bucket or key", http.StatusBadRequest)
		return
	}

	switch r.Method {
	case "POST", "PUT":
		data, err := ioutil.ReadAll(r.Body)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = s.Put(vars["bucket"], vars["key"], r.Header.Get("Content-Type"), data)
		w.WriteHeader(http.StatusOK)
	case "GET":
		ct, data, err := s.Get(vars["bucket"], vars["key"])
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Header().Add("Content-Type", ct)
		w.Write(data)
	}
}

func main() {
	var (
		addr   string
		dbfile string
	)

	flag.StringVar(&addr, "l", ":9988", "Address to listen on")
	flag.StringVar(&dbfile, "db", "/var/data/bolt.db", "Bolt DB file")
	flag.Parse()

	log.Println("Using Bolt DB file:", dbfile)
	log.Println("Listening on:", addr)

	server, err := newServer(dbfile)
	if err != nil {
		log.Fatalf("Error: %s", err)
	}

	router := mux.NewRouter()
	router.Handle("/v1/buckets/{bucket}/keys/{key}", server)
	http.Handle("/", router)

	log.Fatal(http.ListenAndServe(addr, nil))
}

希望对你有帮助!

英文:

A Bolt database is usually embedded into a larger program and is not used over the network like you would with shared databases (think SQLite vs MySQL). Using Bolt is a bit like having a persistent map[[]byte][]byte if that were possible. Depending on what you are doing, you might want to just use something like Redis.

That said, if you need to use Bolt this way, it is not very difficult to wrap with a simple server. Here is an example that writes/reads keys from a Bolt DB over HTTP. You can use Keep-Alive for connection pooling.

Code at: https://github.com/skyec/boltdb-server

package main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"time"
"github.com/boltdb/bolt"
"github.com/gorilla/mux"
)
type server struct {
db *bolt.DB
}
func newServer(filename string) (s *server, err error) {
s = &server{}
s.db, err = bolt.Open(filename, 0600, &bolt.Options{Timeout: 1 * time.Second})
return
}
func (s *server) Put(bucket, key, contentType string, val []byte) error {
return s.db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists([]byte(bucket))
if err != nil {
return err
}
if err = b.Put([]byte(key), val); err != nil {
return err
}
return b.Put([]byte(fmt.Sprintf("%s-ContentType", key)), []byte(contentType))
})
}
func (s *server) Get(bucket, key string) (ct string, data []byte, err error) {
s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(bucket))
r := b.Get([]byte(key))
if r != nil {
data = make([]byte, len(r))
copy(data, r)
}
r = b.Get([]byte(fmt.Sprintf("%s-ContentType", key)))
ct = string(r)
return nil
})
return
}
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
if vars["bucket"] == "" || vars["key"] == "" {
http.Error(w, "Missing bucket or key", http.StatusBadRequest)
return
}
switch r.Method {
case "POST", "PUT":
data, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
err = s.Put(vars["bucket"], vars["key"], r.Header.Get("Content-Type"), data)
w.WriteHeader(http.StatusOK)
case "GET":
ct, data, err := s.Get(vars["bucket"], vars["key"])
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", ct)
w.Write(data)
}
}
func main() {
var (
addr   string
dbfile string
)
flag.StringVar(&addr, "l", ":9988", "Address to listen on")
flag.StringVar(&dbfile, "db", "/var/data/bolt.db", "Bolt DB file")
flag.Parse()
log.Println("Using Bolt DB file:", dbfile)
log.Println("Listening on:", addr)
server, err := newServer(dbfile)
if err != nil {
log.Fatalf("Error: %s", err)
}
router := mux.NewRouter()
router.Handle("/v1/buckets/{bucket}/keys/{key}", server)
http.Handle("/", router)
log.Fatal(http.ListenAndServe(addr, nil))
}

答案2

得分: 4

在boltdb中没有连接池的概念,因为没有连接。它不是一个客户端/服务器数据库,而是一个嵌入式数据库(类似于sqlite或Berkeley-DB)。

Boltdb的设计使得同一进程的多个goroutine可以同时访问数据库(使用不同的事务)。模型是单写多读。Boltdb不支持多进程访问。

如果你需要一个Go程序能够同时从多个进程访问支持的嵌入式数据库,你可以看一下对LMDB的封装,比如:

英文:

There is no connection pooling concept in boltdb, because there is no connection. It is not a client/server database, it is an embedded database (like sqlite or Berkeley-DB).

Boltdb is designed so that multiple goroutines of the same process can access the database at the same time (using different transactions). The model is single writer, multiple readers. Boltdb is not designed to support accesses from multiple processes.

If you need a Go program to use an embedded database supporting access from multiple processes at the same time, you may want to have a look at the wrappers over LMDB, such as:

huangapple
  • 本文由 发表于 2015年6月8日 18:49:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/30707208.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定