应用程序通过 put 将 key 和 value 存储到 etcd 集群中。每个存储的密钥都通过 Raft 协议复制到所有 etcd 集群成员,以实现一致性和可靠性。
package main
import (
"context"
"fmt"
"time"
"github.com/coreos/etcd/clientv3"
)
func main() {
config := clientv3.Config{
Endpoints: []string{"127.0.0.1:2379"}, // 集群列表
DialTimeout: 5 * time.Second,
}
// 建立一个客户端
client, err := clientv3.New(config)
if err != nil {
fmt.Println(err)
return
}
// 用于读写etcd的键值对
kv := clientv3.NewKV(client)
// clientv3.WithPrevKV() 是一个可选控制项,用于获取在设置当前键值对之前的该键的键值对
// 有了该控制项后,putResp 才有 PrevKv 的属性,即获取之前的键值对。
// context.TODO() 表示当前还不知道用哪个 context 控制该操作,先用该字段占位
putResp, err := kv.Put(context.TODO(), "/demo/A/B", "hello", clientv3.WithPrevKV())
if err != nil {
fmt.Println(err)
}
fmt.Println("putResp is ", putResp)
fmt.Println("Revision:", putResp.Header.Revision)
if putResp.PrevKv != nil {
fmt.Println("PrevValue:", string(putResp.PrevKv.Value))
}
putResp, err = kv.Put(context.TODO(),"/test/key1", "Hello etcd!")
if err != nil{
fmt.print("put failed!")
}
kv.Put(context.TODO(),"/test/key2", "Hello World!")
// 再写一个同前缀的干扰项
kv.Put(context.TODO(), "/testspam", "spam")
}
函数声明如下:
// Get retrieves keys.
// By default, Get will return the value for "key", if any.
// When passed WithRange(end), Get will return the keys in the range [key, end).
// When passed WithFromKey(), Get returns keys greater than or equal to key.
// When passed WithRev(rev) with rev > 0, Get retrieves keys at the given revision;
// if the required revision is compacted, the request will fail with ErrCompacted .
// When passed WithLimit(limit), the number of returned keys is bounded by limit.
// When passed WithSort(), the keys will be sorted.
Get(ctx context.Context, key string, opts ...OpOption) (*GetResponse, error)
这里 err 并不能反馈出 key 是否存在(只能反馈出本次操作因为各种原因异常了),我们需要通过 GetResponse 判断 key 是否存在
package main
import (
"context"
"fmt"
"time"
"github.com/coreos/etcd/clientv3"
)
func main() {
config := clientv3.Config{
Endpoints: []string{"192.168.0.113:2379"}, // 集群列表
DialTimeout: 5 * time.Second,
}
// 建立一个客户端
client, err := clientv3.New(config)
if err != nil {
fmt.Println(err)
return
}
// 用于读写etcd的键值对
kv := clientv3.NewKV(client)
kv.Put(context.TODO(), "/demo/A/B", "BBB", clientv3.WithPrevKV())
kv.Put(context.TODO(), "/demo/A/C", "CCC", clientv3.WithPrevKV())
// 读取/demo/A/为前缀的所有key
// clientv3.WithPrefix() , clientv3.WithCountOnly() 可以有多个并以 逗号分隔即可
getResp, err := kv.Get(context.TODO(), "/demo/A/", clientv3.WithPrefix() /*,clientv3.WithCountOnly()*/)
if err != nil {
fmt.Println(err)
}
fmt.Println(getResp.Kvs, getResp.Count)
for _, resp := range getResp.Kvs {
fmt.Printf("key: %s, value:%s\n", string(resp.Key), string(resp.Value))
}
}
package main
import (
"context"
"fmt"
"time"
"github.com/coreos/etcd/clientv3"
)
func main() {
config := clientv3.Config{
Endpoints: []string{"192.168.0.113:2379"}, // 集群列表
DialTimeout: 5 * time.Second,
}
// 建立一个客户端
client, err := clientv3.New(config)
if err != nil {
fmt.Println(err)
return
}
// 用于读写etcd的键值对
kv := clientv3.NewKV(client)
kv.Put(context.TODO(), "/demo/A/B1", "BBB", clientv3.WithPrevKV())
kv.Put(context.TODO(), "/demo/A/B2", "CCC", clientv3.WithPrevKV())
kv.Put(context.TODO(), "/demo/A/B3", "DDD", clientv3.WithPrevKV())
/*
clientv3.WithFromKey() 表示针对的key操作是大于等于当前给定的key
clientv3.WithPrevKV() 表示返回的 response 中含有之前删除的值,否则
下面的 delResp.PrevKvs 为空
*/
delResp, err := kv.Delete(context.TODO(), "/demo/A/B",
clientv3.WithFromKey(), clientv3.WithPrevKV())
if err != nil {
fmt.Println(err)
}
// 查看被删除的 key 和 value 是什么
if delResp.PrevKvs != nil {
// if len(delResp.PrevKvs) != 0 {
for _, kvpair := range delResp.PrevKvs {
fmt.Println("已删除:", string(kvpair.Key), string(kvpair.Value))
}
}
}