ZooKeeper_7_Java操作ZK_获取数据

获取数据


获取数据,包括节点列表的获取节点数据的获取


getChildren

ZooKeeper客户端提供了八个接口,让我们来获取一个节点下的所有子节点:

getChildren(String path, boolean watch)

getChildren(String path, boolean watch, Children2Callback cb, Object ctx)

getChildren(String path, boolean watch, ChildrenCallback cb, Object ctx)

getChildren(String path, boolean watch, Stat stat)


getChildren(String path, Watcher watcher)

getChildren(String path, Watcher watcher, Children2Callback cb, Object ctx)

getChildren(String path, Watcher watcher, ChildrenCallback cb, Object ctx)

getChildren(String path, Watcher watcher, Stat stat)


我们来看下参数:

path

指定数据节点的节点路径

watcher

注册的watcher

(一旦在本次节点获取之后,子节点列表发生变更的话,那么就会像客户端发送通知,该参数允许传入null)

watch

表明是否需要注册一个watcher

在上面<创建会话>中我们提到过一个默认watcher的概念(就是构造zookeeper对象时,传入的watcher接口实现类,作为默认watcher)

这里我们使用该默认watcher

如果参数为true,那么zookeeper客户端会自动使用上文中默认的watcher

如果参数为false,那就表明不需要注册watcher

 

其实这里还是有点迷惑,这个参数和watcher参数是否是关联使用的??

cb

注册一个异步回调函数

ctx

用于传递上下文信息的对象

stat

指定数据节点的状态信息。

在接口中传入一个旧的stat变量,该stat变量会在方法执行过程中,被来自服务端响应的新stat对象替换。


咱们来看看注册Watcher,如果ZooKeeper客户端在获取到指定节点的子节点列表后,还需要订阅这个子节点列表的变化通知,那么就可以通过注册一个watcher来实现。

当子节点被添加或删除时,服务端就会向客户端发送一个NodeChildrenChanged类型的事件通知。

不过需要注意,在服务端发送给客户端的事件通知中,不会包含最新的节点列表,客户端必须主动重新获取


stat对象中记录将一个节点的基本属性信息。

有时我们不仅需要获取子节点的列表,还要获取这个节点最新的节点状态信息,对于这种情况,我们可以将一个旧的stat变量传入API接口,该stat变量会在方法执行过程中,来自服务端响应的新stat对象替换。


上面讲了这么多理论,我们来看代码:

public class TestGetData implements Watcher {

	// 屏障,计数器
	private static CountDownLatch downLatch = new CountDownLatch(1);

	private static ZooKeeper zookeeper = null;

	public static void main(String[] args) throws Exception {

	zookeeper = new ZooKeeper("10.0.227.66:2181", 5000, new TestGetData());

	System.out.println("zookeeper.getState()1 : " + zookeeper.getState());

	try {
			downLatch.await();// 在计数器未归零之前,所有线程等待
	} catch (Exception e) {
			e.printStackTrace();
	}

	System.out.println("zookeeper.getState()2 : " + zookeeper.getState());

	zookeeper.create("/cyx", "ccc".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

	zookeeper.create("/cyx/1", "111".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
	zookeeper.create("/cyx/2", "222".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
	zookeeper.create("/cyx/3", "333".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

	Thread.sleep(5000);

	List<String> childrens = zookeeper.getChildren("/cyx", true);
	System.out.println("childrens : " + childrens);

	Thread.sleep(5000);

	zookeeper.create("/cyx/4", "444".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

	Thread.sleep(8000);

	}

	@Override
	public void process(WatchedEvent event) {

	System.out.println("receive watched event : " + event);

	if (KeeperState.SyncConnected == event.getState()) {

	if (EventType.None == event.getType() && null == event.getPath()) {
			downLatch.countDown();// 计数器-1
	} else if (event.getType() == EventType.NodeChildrenChanged) {// 子节点改变

	try {
			System.out.println("回调输出:" + zookeeper.getChildren(event.getPath(), true));
	} catch (Exception e) {
			e.printStackTrace();
	}
	}

	}
	}
}
输出结果:
zookeeper.getState()1 : CONNECTING
receive watched event : WatchedEvent state:SyncConnected type:None path:null
zookeeper.getState()2 : CONNECTED
childrens : [1, 2, 3]
receive watched event : WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/cyx
回调输出:[1, 2, 3, 4]
上面这段代码我首先创建一个"/cyx"节点

然后在这个节点下,再创建三个子节点,睡上一会儿,然后获取子节点列表,并且订阅,再睡一会儿。

然后创建第四个子节点,这时候process()回调方法被调用...

执行process()方法中的业务。

这里需要注意:Watcher通知时一次性的,即一旦触发一次通知后,该Watcher就失效了,因此客户端需要反复注册watcher



getData

客户端可以通过ZooKeeper来获取一个节点中的数据内容。


同步获取

byte[] getData(final String path, Watcher watcher, Stat stat)

byte[] getData(String path, boolean watch, Stat stat)


异步

void getData(final String path, Watcher watcher, DataCallback cb, Object ctx)void getData(String path, boolean watch, DataCallback cb, Object ctx)


我们来了解下参数:

path

数据节点的节点路径

watcher

注册的watcher,一旦内容有变,就会想客户端发送通知,允许null

stat

指定数据节点的节点状态信息。

watch

表明是否需要注册一个Watcher

cb

注册一个异步回调函数

ctx

用于传递上下文信息的对象


这个使用方法和上面的getChildren差不多..

我们看下注册对的watcher有什么不同:

客户端在获取一个节点的数据内容时,也是可以进行watcher注册对的。

这样当该节点的状态发生变化,那么zookeeper服务端就会向客户端发送一个NodeDataChanged的事件通知。


我们来看个Demo:

同步获取

public class TestGetData2 implements Watcher {

// 屏障,计数器
private static CountDownLatch downLatch = new CountDownLatch(1);

private static ZooKeeper zookeeper = null;

private static Stat stat = new Stat();

public static void main(String[] args) throws Exception {

	zookeeper = new ZooKeeper("10.0.227.66:2181", 5000, new TestGetData2());

	System.out.println("zookeeper.getState()1 : " + zookeeper.getState());

	try {
			downLatch.await();// 在计数器未归零之前,所有线程等待
	} catch (Exception e) {
			e.printStackTrace();
	}

	System.out.println("zookeeper.getState()2 : " + zookeeper.getState());

	zookeeper.create("/cyx", "ccc".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

	System.out.println(new String(zookeeper.getData("/cyx", new TestGetData2(), stat)));

	System.out.println(stat.getCzxid() + " , " + stat.getMzxid() + " , " + stat.getVersion());

	zookeeper.setData("/cyx", "999999".getBytes(), -1);

	Thread.sleep(Integer.MAX_VALUE);

}

@Override
public void process(WatchedEvent event) {

	System.out.println("receive watched event : " + event);

	if (KeeperState.SyncConnected == event.getState()) {

	if (EventType.None == event.getType() && null == event.getPath()) {

	downLatch.countDown();// 计数器-1

	} else if (event.getType() == EventType.NodeDataChanged) {// 节点数据内容改变

	try {

	System.out.println("回调输出 :" + new String(zookeeper.getData(event.getPath(), true, stat)));

	System.out.println("回调输出 :" + stat.getCzxid() + " , " + stat.getMzxid() + " , " + stat.getVersion());

	} catch (Exception e) {
			e.printStackTrace();
	}
	}

	}
}
}

输出结果:
zookeeper.getState()1 : CONNECTING
receive watched event : WatchedEvent state:SyncConnected type:None path:null
zookeeper.getState()2 : CONNECTED
ccc
197568501442 , 197568501442 , 0
receive watched event : WatchedEvent state:SyncConnected type:NodeDataChanged path:/cyx
回调输出 :999999
回调输出 :197568501442 , 197568501443 , 1

我们看下这个代码:

a. 首先创建"/cyx"节点,并且设置节点数据为"ccc"

b. 接着我们通过getData()获取"/cyx"节点中的数据,并增加监听

c. 然后我们手动对"/cyx"节点中的数据进行修改,以此触发回调函数。

d. 最后回调函数process()被调用

异步获取

public class TestGetData3 implements Watcher {

// 屏障,计数器
private static CountDownLatch downLatch = new CountDownLatch(1);

private static ZooKeeper zookeeper = null;

public static void main(String[] args) throws Exception {

	zookeeper = new ZooKeeper("10.0.227.66:2181", 5000, new TestGetData3());

	System.out.println("zookeeper.getState()1 : " + zookeeper.getState());

	try {
			downLatch.await();// 在计数器未归零之前,所有线程等待
	} catch (Exception e) {
			e.printStackTrace();
	}

	System.out.println("zookeeper.getState()2 : " + zookeeper.getState());

	zookeeper.create("/cyx", "ccc".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

	zookeeper.getData("/cyx", true, new MyDataCallBack(), null);

	zookeeper.setData("/cyx", "999999".getBytes(), -1);

	Thread.sleep(Integer.MAX_VALUE);

}

@Override
public void process(WatchedEvent event) {

	System.out.println("receive watched event : " + event);

	if (KeeperState.SyncConnected == event.getState()) {

	if (EventType.None == event.getType() && null == event.getPath()) {

	downLatch.countDown();// 计数器-1

	} else if (event.getType() == EventType.NodeDataChanged) {// 节点数据内容改变

	try {

	zookeeper.getData(event.getPath(), true, new MyDataCallBack(), null);

	} catch (Exception e) {
			e.printStackTrace();
	}
	}
	}
}

static class MyDataCallBack implements AsyncCallback.DataCallback {

	@Override
	public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {

	System.out.println(rc + " , " + path + " , " + new String(data));

	System.out.println(stat.getCzxid() + " , " + stat.getMzxid() + " , " + stat.getVersion());

	}

}

}
输出结果:
zookeeper.getState()1 : CONNECTING
receive watched event : WatchedEvent state:SyncConnected type:None path:null
zookeeper.getState()2 : CONNECTED
0 , /cyx , ccc
197568501447 , 197568501447 , 0
receive watched event : WatchedEvent state:SyncConnected type:NodeDataChanged path:/cyx
0 , /cyx , 999999
197568501447 , 197568501448 , 1

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值