This document guides you on how to use Go Client through some simple examples. For more details, please visit client-go wiki.
Try the transactional key-value API
The txnkv
package provides a transactional API against TiKV cluster.
Create Client
The topology of a TiKV cluster can be discovered by PD server. After starting a TiKV cluster successfully, we can use PD’s address list to create a client to interact with it.
import "github.com/tikv/client-go/v2/txnkv"
client, err := txnkv.NewClient([]string{"127.0.0.1:2379"})
Closing Client
When you are done with a client, you need to gracefully close the client to finish pending tasks and terminate all background jobs.
// ... create a client as described above ...
// ... do something with the client ...
if err := client.Close(); err != nil {
// ... handle error ...
}
Starting Transaction
When using the transactional API, almost all read and write operations are done within a transaction (or a snapshot). You can use Begin
to start a transaction.
txn, err := client.Begin(opts...)
if err != nil {
// ... handle error ...
}
Reads
TxnKV
provides Get
, BatchGet
, Iter
and IterReverse
methods to query TiKV.
Get
retrieves a key-value record from TiKV.
import tikverr "github.com/tikv/client-go/v2/error"
v, err := txn.Get(context.TODO(), []byte("foo"))
if tikverr.IsErrNotFound(err) {
// ... handle not found ...
} else if err != nil {
// ... handle other errors ...
}
// ... handle value v ...
When reading multiple keys from TiKV, BatchGet
can be used.
values, err := txn.BatchGet(context.TODO(), keys)
if err != nil {
// ... handle error ...
}
for _, k := range keys {
if v, ok := values[string(k)]; ok {
// ... handle record k:v ...
} else {
// ... k does not exist ...
}
}
All key-value records are logically arranged in sorted order. The iterators allow applications to do range scans on TiKV. The iterator yields records in the range [start, end)
.
iter, err := txn.Iter(start, end)
if err != nil {
// ... handle error ...
}
defer iter.Close()
for iter.Valid() {
k, v := iter.Key(), iter.Value()
// ... handle record k:v
if err := iter.Next(); err != nil {
// ... handle error ...
}
}
IterReverse
also creates an iterator instance, but it iterates in reverse order.
Writes
You can use Set
and Delete
methods to write data into the transaction.
if err := txn.Set([]byte("foo"), []byte("bar")); err != nil {
// ... handle error ...
}
if err := txn.Delete([]byte("foo")); err != nil {
// ... handle error ...
}
Committing or Rolling Back Transaction
To actually commit the transaction to TiKV, you need to call Commit
to trigger the commit process.
If the transaction does not need to commit, for optimistic transactions, you can just discard the transaction instance, for pessimistic transactions you need to actively call the Rollback()
method to clean up the data previously sent to TiKV.
if err := txn.Commit(context.TODO()); err != nil {
// ... handle error ...
}
// ... commit success ...
Snapshots (Read-Only Transactions)
If you want to create a read-only transaction, you can use GetSnapshot
method to create a snapshot. A Snapshot
is more lightweight than a transaction.
ts, err := client.CurrentTimestamp("global")
if err != nil {
// ... handle error ...
}
snapshot := client.GetSnapshot(ts)
v, err := snapshot.Get(context.TODO(), []byte("foo"))
// ... handle Get result ...
Snapshot can also be extracted from an existing transaction.
snapshot := txn.GetSnapshot()
// ... use snapshot ...
Try the Raw key-value API
Create client
After starting a TiKV cluster successfully, we can use PD’s address list to create a client to interact with it.
import (
"github.com/tikv/client-go/v2/rawkv"
)
client, err := rawkv.NewClientWithOpts(context.TODO(), []string{"127.0.0.1:2379"})
if err != nil {
// ... handle error ...
}
Closing Client
When you are done with a client, you need to gracefully close the client to finish pending tasks and terminate all background jobs.
if err := client.Close(); err != nil {
// ... handle error ...
}
Single Key Read/Write
RawKV
provides Get
, Put
and Delete
methods to read and write a single key.
v, err := client.Get(context.TODO(), []byte("key"))
if err != nil {
// ... handle error ...
}
if v == nil {
// ... handle not found ...
} else {
// ... handle value v ...
}
err = client.Put(context.TODO(), []byte("key"), []byte("value"))
if err != nil {
// ... handle error ...
}
err = client.Delete(context.TODO(), []byte("key"))
if err != nil {
// ... handle error ...
}
Iterations
Like txnkv
, there are also Scan
and ReverseScan
methods to iterate over a range of keys.
keys, values, err := client.Scan(context.TODO(), []byte("begin"), []byte("end"), 10)
if err != nil {
// ... handle error ...
}
// ... handle keys, values ...
keys, values, err := client.ReverseScan(context.TODO(), []byte("end"), []byte("begin"), 10)
if err != nil {
// ... handle error ...
}
// ... handle keys, values ...
Batch Operations
RawKV
also supports batch operations using batch. Note that since RawKV
does not provide transaction semantic, we do not guarantee that all writes will succeed or fail at the same time when these keys are distributed across multiple regions.
values, err := client.BatchGet(context.TODO(), [][]byte{[]byte("key1"), []byte("key2")})
if err != nil {
// ... handle error ...
}
// ... handle values ...
err = client.BatchPut(context.TODO(), [][]byte{[]byte("key1"), []byte("key2")}, [][]byte{[]byte("value1"), []byte("value2")})
if err != nil {
// ... handle error ...
}
err = client.BatchDelete(context.TODO(), [][]byte{[]byte("key1"), []byte("key2")})
if err != nil {
// ... handle error ...
}