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