go-memdb
提供 memdb 包,它实现了一个建立在不可改变的 radix 树上的简单内存数据库。该数据库提供原子性、一致性和与 ACID 隔离。由于是内存数据库,它不提供耐久性。数据库被实例化时有一个模式,该模式指定了存在的表和索引,并允许执行事务。
数据库提供了以下功能:
- 多版本并发控制(MVCC)-- 通过利用不可变的 radix 树,数据库能够支持任何数量的并发读取器,而不需要锁定,并允许写入器取得进展。
- 事务支持 -- 数据库允许丰富的事务,其中插入、更新或删除多个对象。事务可以跨越多个表,并以原子方式应用。数据库在ACID术语中提供了原子性和隔离性,因此在提交之前,更新是不可见的。
- 丰富的索引 -- 表可以支持任意数量的索引,可以是简单的如单字段索引,也可以是更高级的复合字段索引。某些类型,如UUID,可以有效地从字符串压缩成字节索引,以减少存储需求。
- 监视 -- 调用者可以填充一个监视集作为查询的一部分,它可以用来检测何时对数据库进行了影响查询结果的修改。这让调用者可以很容易地以一种非常通用的方式观察数据库的变化。
关于底层的不可改变的 radix 树,请参见 go-immutable-radix。
文档
完整的文档可以在 Godoc 上找到。
例子
下面是一个简单的使用实例:
// Create a sample struct
type Person struct {
Email string
Name string
Age int
}
// Create the DB schema
schema := &memdb.DBSchema{
Tables: map[string]*memdb.TableSchema{
"person": &memdb.TableSchema{
Name: "person",
Indexes: map[string]*memdb.IndexSchema{
"id": &memdb.IndexSchema{
Name: "id",
Unique: true,
Indexer: &memdb.StringFieldIndex{Field: "Email"},
},
"age": &memdb.IndexSchema{
Name: "age",
Unique: false,
Indexer: &memdb.IntFieldIndex{Field: "Age"},
},
},
},
},
}
// Create a new data base
db, err := memdb.NewMemDB(schema)
if err != nil {
panic(err)
}
// Create a write transaction
txn := db.Txn(true)
// Insert some people
people := []*Person{
&Person{"joe@aol.com", "Joe", 30},
&Person{"lucy@aol.com", "Lucy", 35},
&Person{"tariq@aol.com", "Tariq", 21},
&Person{"dorothy@aol.com", "Dorothy", 53},
}
for _, p := range people {
if err := txn.Insert("person", p); err != nil {
panic(err)
}
}
// Commit the transaction
txn.Commit()
// Create read-only transaction
txn = db.Txn(false)
defer txn.Abort()
// Lookup by email
raw, err := txn.First("person", "id", "joe@aol.com")
if err != nil {
panic(err)
}
// Say hi!
fmt.Printf("Hello %s!\n", raw.(*Person).Name)
// List all the people
it, err := txn.Get("person", "id")
if err != nil {
panic(err)
}
fmt.Println("All the people:")
for obj := it.Next(); obj != nil; obj = it.Next() {
p := obj.(*Person)
fmt.Printf(" %s\n", p.Name)
}
// Range scan over people with ages between 25 and 35 inclusive
it, err = txn.LowerBound("person", "age", 25)
if err != nil {
panic(err)
}
fmt.Println("People aged 25 - 35:")
for obj := it.Next(); obj != nil; obj = it.Next() {
p := obj.(*Person)
if p.Age > 35 {
break
}
fmt.Printf(" %s is aged %d\n", p.Name, p.Age)
}
// Output:
// Hello Joe!
// All the people:
// Dorothy
// Joe
// Lucy
// Tariq
// People aged 25 - 35:
// Joe is aged 30
// Lucy is aged 35