-
Notifications
You must be signed in to change notification settings - Fork 222
TxnKV Basic
The txnkv
package provides a transactional API against TiKV cluster.
Information about a TiKV cluster can be found by the address of PD server. After starting a TiKV cluster successfully, we can use PD's address list to create a client to interact with it. The following code demonstrate the process of creating a txnkv client.
import "github.com/tikv/client-go/v2/txnkv"
client, err := txnkv.NewClient([]string{"127.0.0.1:2379"})
When you are done with a client, you need to gracefully close the client to finish pending tasks and terminate all background jobs.
Example:
// ... create a client as described above ...
// ... do something with the client ...
if err := client.Close(); err != nil {
// ... handle error ...
}
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 ...
}
// ... use txn for read and write ...
The Begin
process gets a timestamp from PD as the StartTS
of the transaction and does some necessary initialization of the transaction object, such as allocating MemBuffer
for buffering subsequent writes.
Begin
currently supports two options. WithTxnScope
is used to specify the scope of the transaction, for more details please refer to Advanced Operations. WithStartTS
is used to specify the StartTS
of the transaction, this option is usually used to create read-only transactions that read historical versions.
In this section we will only discuss the case where optimistic locking is used. All writes are buffered on the client until the transaction is committed.
TxnKV
provides Get
, BatchGet
, Iter
and IterReverse
methods to query TiKV.
Get
retrives a key-value record from TiKV. If this transaction has buffered (pending commit) writes, Get
will read the data in the MemBuffer
first. Specially, Get
returns ErrNotExists
if there is a buffered delete operation for this record.
import tikverr "github.com/tikv/client-go/v2/error"
v, err := txn.Get(context.TODO(), []byte("foo"))
if tikverr.IsErrNotFound(err) {
// ... handle not found ...
}
if err != nil {
// ... handle other errors ...
}
// ... handle value v ...
When reading multiple keys from TiKV, BatchGet
can be used. It returns a key-value map, and when a key does not exist, it does not appear in the map.
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 in TiKV. The iterators allow applications to do range scans on TiKV. The iterator yields records in the range [start, end)
. Start key and end key are arbitrary bytes. Nil
key stands for "" when used as start key, and stands for +inf
when used as end key.
Like Get
and BatchGet
, if the transaction has buffered writes, the iterator will read the data in the MemBuffer
first.
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 ...
}
}
// ... iteration stops ...
IterReverse
also creates an iterator instance, but it iterates in reverse order. Note in particular that the end key is exclusive. That is, the first record returned by iterator is the last record in the range [start, end)
.
You can use Set
and Delete
methods to write data into the transaction. Currently, due to the limitation of MemBuffer
implementation, empty value is not allowed. If you try to set empty value, ErrCannotSetNilValue
will be returned.
Example:
if err := txn.Set([]byte("foo"), []byte("bar")); err != nil {
// ... handle error ...
}
if err := txn.Delete([]byte("foo")); err != nil {
// ... handle error ...
}
To actually commit the transaction to TiKV, you need to call Commit
to trigger the two-phase 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 ...
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. It does not have an embeded MemBuffer
and all reads are done directly from TiKV.
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 a existed transaction.
snapshot := txn.GetSnapshot()
// ... use snapshot ...
Feel free to help improving! Minor changes are warmly welcomed. Just simply click edit!
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Contents
- Client-Go Wiki
- Compatibility
- API V2
- Transactional API
- RawKV API
- Configurations
- Utilities