本文共 1927 字,大约阅读时间需要 6 分钟。
之前有文章写了Zookeeper 通过节点是否存在进行互斥,实现悲观锁
这次来说说如何安全的修改数据。ZNode中 Stat结构:
- cZxid:这是导致创建znode更改的事务ID。
- mZxid:这是最后修改znode更改的事务ID。
- pZxid:这是用于添加或删除子节点的znode更改的事务ID。
- ctime:(Create TIme) 表示从1970-01-01T00:00:00Z开始以毫秒为单位的znode创建时间。
- mtime:(Modify Time) 表示从1970-01-01T00:00:00Z开始以毫秒为单位的znode最近修改>*时间。
- dataVersion:表示对该znode的数据所做的更改次数。
- cversion:这表示对此znode的子节点进行的更改次数。
- aclVersion:表示对此znode的ACL进行更改的次数。
- ephemeralOwner:如果znode是ephemeral类型节点,则这是znode所有者的 session ID。 如果znode不是ephemeral节点,则该字段设置为零。
- dataLength:这是znode数据字段的长度。
- numChildren:这表示znode的子节点的数量。
原理就是先获取数据并且获取到Stat,然后尝试修改数据时传入Stat的dataVersion,如果version不同 就会抛出 BadVersion 异常
CuratorFramework client = CuratorFrameworkFactory.builder() .connectString("192.168.0.111:2181") .sessionTimeoutMs(10000).retryPolicy(new RetryNTimes(3, 1000)).build(); .namespace("test").build(); client.start(); try { byte[] data = "我是消息".getBytes(); client.create().creatingParentsIfNeeded() .withMode(CreateMode.EPHEMERAL) .forPath("/shepi", data); } catch (Exception isIgnored){ } //我们的本意是,如果这个节点的内容为 我是消息,那么就可以修改 byte[] data = client.getData().forPath("/shepi"); if (String.valueOf(data).equals("我是消息")){ client.setData().forPath("/shepi", "改掉了".getBytes()); }
上面的例子有个问题,就是在判断data内容是否相同时,如果其他session手动修改了数据呢?
Stat stat = new Stat(); for(;;){ byte[] data = client.getData().storingStatIn(stat).forPath("/shepi"); if (String.valueOf(data).equals("我是消息")){ try{ client.setData().withVersion(stat.getVersion()).forPath("/shepi", "改掉了".getBytes()); return; //没出异常说明修改成功直接返回 } catch (KeeperException.BadVersionException ignored){ //进行重新尝试 System.out.println("修改失败了"); } }else{ System.out.println("已经被别人修改过了"); return; } }
转载地址:http://cxlsi.baihongyu.com/