badfer — это быстрая встроенная база данных K/V, реализованная на чистом Go и оптимизированная для LSM-дерева.
Установить
$ go get github.com/dgraph-io/badger/...
база данных
открыть базу данных
opts := badger.DefaultOptions
opts.Dir = "/tmp/badger"
opts.ValueDir = "/tmp/badger"
db, err := badger.Open(opts)
if err != nil {
log.Fatal(err)
}
defer db.Close()
место хранения
магазин кв
Использование метода Txn.Set()
err := db.Update(func(txn *badger.Txn) error {
err := txn.Set([]byte("answer"), []byte("42"))
return err
})
Пакетные настройки
wb := db.NewWriteBatch()
defer wb.Cancel()
for i := 0; i < N; i++ {
err := wb.Set(key(i), value(i), 0) // Will create txns as needed.
handle(err)
}
handle(wb.Flush()) // Wait for all txns to finish.
WriteBatch не разрешает чтение. Для чтения-изменения-записи следует использовать транзакционный API.
Установить время жизни TTL
Badger позволяет установить дополнительное значение времени жизни (TTL) для ключа. Как только TTL закончится, KEY больше нельзя будет восстановить, и он будет удален сборщиком мусора. TTL можно установить равным единице с помощью Txn.SetWithTTL().time.Duration
значение
установить метаданные
Txn.SetWithMeta()
Установить пользовательские метаданные
использоватьTxn.SetEntry()
Ключ, значение, пользовательские метаданные и TTL могут быть установлены одновременно.
перебирать ключи
Для перебора ключей мы можем использовать итератор, что можно сделать с помощьюМетод Txn.NewIterator() получает итератор. Итерация происходит в байтовом лексикографическом порядке.
err := db.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchSize = 10
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
k := item.Key()
err := item.Value(func(v []byte) error {
fmt.Printf("key=%s, value=%s\n", k, v)
return nil
})
if err != nil {
return err
}
}
return nil
})
сканирование префикса
Для перебора ключевых префиксов вы можете комбинировать Seek() и ValidForPrefix():
db.View(func(txn *badger.Txn) error {
it := txn.NewIterator(badger.DefaultIteratorOptions)
defer it.Close()
prefix := []byte("1234")
for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
item := it.Item()
k := item.Key()
err := item.Value(func(v []byte) error {
fmt.Printf("key=%s, value=%s\n", k, v)
return nil
})
if err != nil {
return err
}
}
return nil
})
Обход ключей
Badger поддерживает уникальный режим итерации, называемый итерацией только по ключу. Это на несколько порядков быстрее, чем обычная итерация, потому что она включает доступ только к lsm-дереву, которое обычно полностью находится в оперативной памяти. Чтобы включить итерацию только по ключу, вам нужно установить IteratorOptions. Поле PrefetchValues ложно. Это также можно использовать для разреженного чтения выбранных ключей во время итерации, вызывая item.Value() только при необходимости.
err := db.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchValues = false
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
k := item.Key()
fmt.Printf("key=%s\n", k)
}
return nil
})
поток данных
Badger предоставляет платформу потоковой передачи, которая может одновременно проходить всю базу данных или ее части, преобразовывать данные в настраиваемые ключи-значения и непрерывно передавать данные для отправки по сети, записи на диск и даже записи в Badger. Это более быстрый способ обхода Badger, чем использование одного итератора. Stream поддерживает Badger как в режиме администратора, так и в обычном режиме.
stream := db.NewStream()
// db.NewStreamAt(readTs) for managed mode.
// -- Optional settings
stream.NumGo = 16 // Set number of goroutines to use for iteration.
stream.Prefix = []byte("some-prefix") // Leave nil for iteration over the whole DB.
stream.LogPrefix = "Badger.Streaming" // For identifying stream logs. Outputs to Logger.
// ChooseKey is called concurrently for every key. If left nil, assumes true by default.
stream.ChooseKey = func(item *badger.Item) bool {
return bytes.HasSuffix(item.Key(), []byte("er"))
}
// KeyToList is called concurrently for chosen keys. This can be used to convert
// Badger data into custom key-values. If nil, uses stream.ToList, a default
// implementation, which picks all valid key-values.
stream.KeyToList = nil
// -- End of optional settings.
// Send is called serially, while Stream.Orchestrate is running.
stream.Send = func(list *pb.KVList) error {
return proto.MarshalText(w, list) // Write to w.
}
// Run the stream
if err := stream.Orchestrate(context.Background()); err != nil {
return err
}
// Done.
удалить ключ
использоватьTxn.Delete()
метод удаления ключа
Получить ключевое значение
Получить значение через txn.Get
err := db.View(func(txn *badger.Txn) error {
item, err := txn.Get([]byte("answer"))
handle(err)
var valNot, valCopy []byte
err := item.Value(func(val []byte) error {
// This func with val would only be called if item.Value encounters no error.
// Accessing val here is valid.
fmt.Printf("The answer is: %s\n", val)
// Copying or parsing val is valid.
valCopy = append([]byte{}, val...)
// Assigning val slice to another variable is NOT OK.
valNot = val // Do not do this.
return nil
})
handle(err)
// DO NOT access val here. It is the most common cause of bugs.
fmt.Printf("NEVER do this. %s\n", valNot)
// You must copy it to use it outside item.Value(...).
fmt.Printf("The answer is: %s\n", valCopy)
// Alternatively, you could also use item.ValueCopy().
valCopy, err = item.ValueCopy(nil)
handle(err)
fmt.Printf("The answer is: %s\n", valCopy)
return nil
})
если не существуетTxn.Get()
вернетErrKeyNotFound
ошибка
Обратите внимание, что значение, возвращаемое Get(), действительно только тогда, когда транзакция открыта. Если значение необходимо использовать вне транзакции, оно должно быть скопировано в другой байтовый срез с помощью функции copy().
дела
транзакция только для чтения
Транзакции только для чтения используют метод DB.View()
err := db.View(func(txn *badger.Txn) error {
// Your code here…
return nil
})
Блокировка транзакции чтения-записи
Транзакции чтения и записи могут использовать метод DB.Update().
err := db.Update(func(txn *badger.Txn) error {
// Your code here…
return nil
})
Управляйте транзакциями вручную
Использовать напрямуюDB.NewTransaction()
функция для ручного создания и фиксации транзакций. Он принимает логический параметр, чтобы указать, требуется ли транзакция чтения-записи. Для транзакций чтения и записи вам нужно вызватьTxn.Commit()
чтобы убедиться, что транзакция совершена. Для транзакций только для чтения вызовитеtxn.reject()
Вот и все.commit()
Также называется внутреннимtxn .reject()
для очистки транзакции, поэтому простого вызова Txn.Commit() достаточно для выполнения транзакции чтения-записи.
Однако, если ваш код по какой-то причине (ошибка) не вызываетTxn.Commit()
. Его нужно вызвать в отсрочкеtxn . reject()
// Start a writable transaction.
txn := db.NewTransaction(true)
defer txn.Discard()
// Use the transaction...
err := txn.Set([]byte("answer"), []byte("42"))
if err != nil {
return err
}
// Commit the transaction and check for error.
if err := txn.Commit(); err != nil {
return err
}
Эта статья также опубликована в общедоступной учетной записи WeChat [Trail News]. Пожалуйста, отсканируйте код, чтобы следовать!