转自:Simba_cheng

更新节点数据的方法:

  • 同步方法:Stat setData(final String path, byte data[], int version)
  • 异步方法:void setData(final String path, byte data[], int version, StatCallback cb, Object ctx)

参数说明:

  • path:指定数据节点路径
  • data[]:一个字节数组,即需要使用该数据来覆盖节点现在的数据内容
  • version:指定节点的数据版本
  • cb:注册一个异步回调函数
  • ctx:用于传递上下文信息的对象

其中:

version参数用于指定节点的数据版本,表名本次更新操作是针对指定的数据版本进行的。

指定数据版本更新的意义何在呢?

通俗的讲"CAS":对于值V,每次更新前都会比对其值是否是预期值A,只有符合预期,才会将V原子化的更新到新值B

CAS具体解释
zookeeper的setData接口中的version参数是CAS衍化来的

zookeeper每个节点都有数据版本的概念,在调用更新操作的时候,就可以添加version这个参数,该参数可以对应于CAS

原理中对的"预期值",表明是针对该数据版本进行更新。

 形象一些说:

假如有一个客户端试图进行更新操作,它会携带上次获取到的version值进行更新。

而如果在这段时间内,ZooKeeper服务器上该节点的数值恰好已经被其他客户端更新了,那么其数据版本一定也会发生变化,

因此肯定与客户端携带对的version无法匹配,于是便无法成功更新 -- 因此可以有效地避免一些分布式更新的并发问题

Demo代码:

 public class TestSetData 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 TestSetData()); 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, null); // 第一次设置
Stat stat = zookeeper.setData("/cyx", "456".getBytes(), -1);
System.out.println(stat.getCzxid() + " , " + stat.getMzxid() + " , " + stat.getVersion()); // 第二次设置
Stat stat2 = zookeeper.setData("/cyx", "789".getBytes(), -1);
System.out.println(stat2.getCzxid() + " , " + stat2.getMzxid() + " , " + stat2.getVersion()); // 获取第一次设置得到version,进行更新
try { zookeeper.setData("/cyx", "123".getBytes(), stat.getVersion()); } catch (Exception e) {
e.printStackTrace();
} } @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
}
}
}
}

输出结果:

zookeeper.getState()1 : CONNECTING
receive watched event : WatchedEvent state:SyncConnected type:None path:null
zookeeper.getState()2 : CONNECTED
receive watched event : WatchedEvent state:SyncConnected type:NodeDataChanged path:/cyx
197568501464 , 197568501465 , 1
197568501464 , 197568501466 , 2
org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for /cyx

代码编写思路:

  1. 首先创建节点"/cyx"节点,设置节点参数"ccc"
  2. 接着我们第一次setData,更新节点参数为"456",同时获取stat,此时version已经改变
  3. 然后我们再次setData,更新节点参数为"789",同时获取stat,version也改变了
  4. 接着我们使用第一次获取的version版本号,去setData。
  5. 然后就抛异常,因为第二次setData的时候,版本号已经更新,这时候,我们拿第一次的更新的版本号去更新,是没法成功的。

解释下setData时的"-1"

在ZooKeeper中,数据版本都是从0开始计数额,所以严格的讲,"-1"不是一个合法得到数据版本,它仅仅是一个标示符。

如果客户端传入的版本参数是"-1",就是告诉zookeeper服务器,客户端需要基于数据的最新版本进行更新操作。

最新文章

  1. Python OS模块常用函数说明
  2. 13、Apache中虚拟目录和目录权限配置
  3. 使用sysprep克隆虚拟机
  4. 用NodeJs实现延迟调用,规避定时任务的闭包问题
  5. php基本数据类型需要注意的地方
  6. template might not exist or might not be accessible by any of the configured Template Resolvers
  7. 201521123004 《Java程序设计》第13周学习总结
  8. RxJava(一) create操作符的用法和源码分析
  9. SpringMVC源码分析--容器初始化(五)DispatcherServlet
  10. Jquery EasyUI +Ajax +Json +一般处理程序 实现数据的前台与后台的交互 --- 善良公社项目
  11. nodejs之使用express框架连接mysql数据库,返回jsonapi数据
  12. 使用百度的富文本编辑器UEditor遇到的问题总结
  13. js的几个补充事件
  14. Ubuntu 16.10 server 相关
  15. 提取json响应结果值_后置处理器JSON Extractor
  16. 【OpenGL】第一个窗口
  17. Python3 简单验证码识别思路及实例
  18. 关于gridview改变行内容事件需要点击别的行或控件才能执行
  19. 汇智课堂 Node.js相关课程
  20. quick2.2.6 问题记录

热门文章

  1. vue2.* 事件 定义方法 执行方法 获取数据 改变数据 执行方法传值 以及事件对象 05
  2. Lambda表达式学习(1)
  3. 记录一下mac上码云的使用
  4. HDU 2955 变形较大的01背包(有意思,新思路)
  5. block本质探寻一之内存结构
  6. 【树形DP】洛谷P1352_没有上司的舞会
  7. Tomcat7 新的数据库连接池Tomcat jdbc pool介绍和配置
  8. vue组件引入失败原因之一
  9. 【python】logging日志模块写入中文编码错误解决办法
  10. PyQt5利用QPainter绘制各种图形