一、前言
Curator框架提供了一套高级的API, 简化了ZooKeeper的操作,这里来介绍一下API;
二、Curator常用的API
2.1 连接zookeeper
private CuratorFramework client;
@Before
public void init() {
/**
* 构造方法
* public static CuratorFramework newClient(String connectString, int sessionTimeoutMs, int connectionTimeoutMs, RetryPolicy retryPolicy)
* @param connectString: zookeeper服务列表,ip端口号逗号分隔,格式为 host1:port1,host2:port2,host3:port3
* @param sessionTimeoutMs: 会话超时时间,单位毫秒,默认60000ms
* @param connectionTimeoutMs: 连接创建超时时间,单位毫秒,默认60000ms
* @param retryPolicy: 重试策略,内置四种,可实现自定义重试策略
*/
this.client = CuratorFrameworkFactory.newClient("120.78.215.216:2181", 3000, 3000, new ExponentialBackoffRetry(3000, 3));
this.client.start();
}
2.2 创建节点
@Test
public void addNode() throws Exception{
//创建一个节点
client.create().forPath("/create1");
//创建一个带有初始值的节点,,值类型应为byte[]
client.create().forPath("/create2", "create2".getBytes());
/**
* 创建持久化顺序节点
* CreateMode.
* PERSISTENT(0, false, false), 持久化节点
* PERSISTENT_SEQUENTIAL(2, false, true), 持久化顺序节点
* EPHEMERAL(1, true, false), 临时节点
* EPHEMERAL_SEQUENTIAL(3, true, true); 临时顺序节点
*/
client.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/create3");
client.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/create3");
//在后台执行操作
client.create().inBackground().forPath("/create4");
//递归创建节点,若创建节点的父节点不存在是会报错的
client.create().creatingParentsIfNeeded().forPath("/create5/create6/create7");
client.create().compressed().forPath("/create8");
/**
* 避免在成功创建节点后,在返回客户端结果前服务端崩溃,导致客户端无法的得到当前创建节点的路径响应
* 若创建失败,withProtection() 会进行重试,
* 官方解释 -> ctrl + left mouse button
* @see : http://curator.apache.org/apidocs/org/apache/curator/framework/api/CreateBuilderMain.html#withProtection--
*/
String path = client.create().withProtection().forPath("/create9", "create9".getBytes());
}
运行后的输出:
从左图可以得到如下结论:
1.创建不带初始值的节点时,默认值为ip,
2.创建顺序节点会自动给节点名字后面加序号
2.3 获取节点
@Test
public void getData() throws Exception{
//forPath()返回值为byte[],因此需要new String(byte[] byte)方法转换
client.getData().forPath("/create1");
log.info(String.format("create2 -> %s", new String(client.getData().forPath("/create2"))));
}
2.4 更新节点数据
@Test
public void setData() throws Exception{
//默认值更新节点数据
client.setData().forPath("/setData1");
//给定值更新节点数据
client.setData().forPath("/setData2","setData2".getBytes());
//CAS操作,更新指定数据版本节点数据,更新成功后数据版本+1,若版本不匹配,则更新失败
client.setData().withVersion(21).forPath("/setData2", "setData2".getBytes());
}
2.5 删除节点数据
@Test
public void del() throws Exception{
//删除节点
client.delete().forPath("/create1");
/**
* 递归删除create6节点,create5节点不会被删除,
* 是不可以forPath("/create6")的,需要指明全路径,
* 因为有可能存在/create6节点,与/create5/create6是不同的描述
*/
client.delete().deletingChildrenIfNeeded().forPath("/create5/create6");
//删除指定版本的节点数据
client.delete().withVersion(-1).forPath("/create5");
//guaranteed()类似于创建节点时的withProtection()方法一样,在有效会话内重试删除,直至删除成功
client.delete().guaranteed().forPath("/create7");
}
注: 在更新和删除节点数据的时候都支持CAS及乐观锁(版本号),版本号是从0开始的,默认-1理论上只是用来占位的而已,因此对于指定-1则不会生效;
在对节点数据进行更新是,无论是否指定数据版本,成功更新后版本号都会+1;
2.6 获取子节点
@Test
public void child() throws Exception{
client.create().creatingParentsIfNeeded().forPath("/parent/child1");
client.create().creatingParentsIfNeeded().forPath("/parent/child2");
client.create().creatingParentsIfNeeded().forPath("/parent/child3");
client.create().creatingParentsIfNeeded().forPath("/parent/child4/son1");
//获取指定节点的子节点
List<String> childrens = client.getChildren().forPath("/parent");
log.info(String.format("parent's child node are -> %s", childrens));
}
输出:
parent's child node are -> [child4, child2, child3, child1]
可见,该方法只能获取一级子节点;
2.7 判断节点是否存在
@Test
public void exist() throws Exception{
Stat stat = client.checkExists().forPath("/parent");
log.info("stat ->" + stat.toString());
Stat stat1 = client.checkExists().forPath("/parentNotExist");
log.info("stat1 ->" + stat1.toString());
}
输出:
stat ->10781,10781,1556645668186,1556645668186,0,4,0,0,0,4,10786
java.lang.NullPointerException
at com.river.service.CuratorNodeOperator.exist(CuratorNodeOperator.java:112)
可知若节点不存在,则stat对象为null;
2.8 事务内操作
@Test
public void transaction() throws Exception{
//事务内
//检查节点是否存在
client.inTransaction().check().forPath("/parent")
.and()
//创建节点
.create().forPath("/check")
.and()
//设置节点数据
.setData().forPath("/check","check".getBytes())
.and()
//提交事务
.commit();
}
未完待续...先睡觉了