1 ,使用 idea 创建 maven 项目 :
双击打开 idea - create new Project - maven - next
- 填写 GAV ( G:com.itcast ; A:zkTest ;) - next - finish
2 ,引入 maven 依赖 :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itcast</groupId>
<artifactId>zkTest</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 我们需要写的代码从这里开始 -->
<repositories>
<repository>
<id>cloudera</id>
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.5-cdh5.14.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
</dependencies>
</project>
3 ,建类 :Day01
右键 java - new - 输入 com.heima.zkTest.Day01 - OK
4 ,看到 Day01 这个类 :
5 ,查 – 子节点 : ls /
@Test // ls /
public void ls() throws IOException, KeeperException, InterruptedException {
// String,int,Watcher
// 集群地址,超时等待时间(过了这么久还连接不上的话,就不等了),观察者。
ZooKeeper zk = new ZooKeeper("node01:2181",5000,null);
List<String> list = zk.getChildren("/", null);
for (String s : list) {
System.out.println(s);
}
zk.close();
}
6 ,查 – 数据 : get /xyj
@Test // get /xyj
public void getXyj() throws IOException, InterruptedException, KeeperException {
ZooKeeper zk = new ZooKeeper("node01:2181",5000,null);
byte[] data = zk.getData("/xyj", null, null);
String str = new String(data);
System.out.println(str);
zk.close();
}
7 ,查 – 元数据信息 :
@Test // stat
public void getStat() throws IOException, InterruptedException, KeeperException {
ZooKeeper zk = new ZooKeeper("node01:2181",5000,null);
Stat stat = new Stat();
zk.getData("/xyj", null, stat);
System.out.println("数据版本号:" + stat.getVersion());
System.out.println("节点创建时候的事务 id :" +stat.getCversion());
System.out.println("数据长度:" + stat.getDataLength());
zk.close();
}
8 ,增 : create /a tom
@Test // create /a tom
public void create() throws InterruptedException, IOException, KeeperException {
// 连接
ZooKeeper zk = new ZooKeeper("node01:2181",5000,null);
// 创建节点
if(zk.exists("/a",null)==null){
// 路径,数据(转码成为字节),节点权限( 我们用开放权限 ),保存方式( 我们选永久保存 )
String msg=zk.create("/a","tom".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
System.out.println("创建成功:"+msg);
}else{
System.out.println("节点已经存在,不要重复创建...");
}
zk.close();
}
9 ,改 : set /a jerry
@Test // set /a jerry
public void setA() throws IOException, InterruptedException, KeeperException {
ZooKeeper zk = new ZooKeeper("node01:2181",5000,null);
zk.setData("/a","jerry".getBytes(),-1);
zk.close();
}
10,删 – 单节点: delete /a
@Test // delete /a
public void delete() throws IOException, KeeperException, InterruptedException {
ZooKeeper zk = new ZooKeeper("node01:2181",5000,null);
// 节点,版本号( -1 代表最新版本号 )
zk.delete("/a",-1);
zk.close();
}
11,删 – 目录 :
javaAPI 不提供删除目录的操作
12,理论 1 – 版本号 : 元数据中的版本号
- 修改和删除都需要用到版本号。
- 数据的初始版本号是 0
- 每次修改数据,版本号就会 +1
- 当使用 javaAPI 修改,或这删除数据的时候,需要写版本号,如果写不对版本号,就无法操作数据。
- -1 代表最新版本号,我也不管你现在是什么版本,我就操作你这个数据的最新版本。
- 版本号的用途 :并发修改。
13,高级操作 :并发修改 ( 重点 )
- 先查出来版本号,然后再修改
public static void main(String[] args) throws Exception {
ZooKeeper zk = new ZooKeeper("node01:2181",5000,null);
Stat stat = new Stat();
zk.getData("/a",null,stat);
int version = stat.getVersion();
zk.setData("/a","aa".getBytes(),version);
zk.close();
}
- 修改 12 次,依次修改 :
public static void main(String[] args) throws Exception {
for (int i = 1; i <=12 ; i++) {
ZooKeeper zk = new ZooKeeper("node01:2181",5000,null);
Stat stat = new Stat();
zk.getData("/a",null,stat);
int version = stat.getVersion();
zk.setData("/a","aa".getBytes(),version);
zk.close();
}
}
- 图示:每次修改操作都依次执行,前一次修改结束了,后一次修改才开始进行
- 并发修改 :12 个线程一起修改
结果 :11 个错误。
结论 :1 个用户修改成功,其他 11 个用户全部失败。
public static void main(String[] args) throws IOException {
for (int i=0;i<12;i++){
Thread t = new Thread(new Runnable() {
public void run() {
try {
ZooKeeper zk = new ZooKeeper("node01:2181",5000,null);
Stat stat = new Stat();
zk.getData("/a",null,stat);
int version = stat.getVersion();
zk.setData("/a","aa".getBytes(),version);
zk.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
t.start();
}
}
- 12个线程,分批次修改,每三个线程一组:
public static void main(String[] args) throws Exception {
for (int i = 1; i <=12 ; i++) {
final int j=i;
if(i==4||i==7||i==10){
Thread.sleep(1000);
}
Thread t = new Thread(new Runnable() {
public void run() {
try {
ZooKeeper zk = new ZooKeeper("node01:2181", 5000, null);
Stat stat = new Stat();
zk.getData("/a", null, stat);
int version = stat.getVersion();
zk.setData("/a", "aa".getBytes(), version);
System.out.println(j);
zk.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
t.start();
}
}
- 对同一时刻的理解 :版本图
1 ,用户 1,2,3 就相当于同一时刻在修改
2 ,在 1,2,3 发出修改操作时,他们看到的版本号都是 0
3 ,但是 1 率先开始修改操作
4 ,当 1 号修改完成后,数据的版本号已经变成 1 版本
5 ,2号,3号,手中拿着的版本号仍然是 0 ,但是数据版本号已经是 1 ,所以 2,3 修改失败。
6 ,组内不确定性:每个小组中都有一个跑得快的线程,占据主导地位,另外两个跑得慢,至于小组中的哪一个跑得快,是不确定的。
7 ,时间不确定性:理论上说,线程之间存在竞争激烈的竞争,每个小组会有一个线程获胜,但是有可能修改操作执行的很快,以至于,它执行完后,下一个线程才开始启动,这样的话,一个小组中就有可能修改两次数据。
- 版本号的作用 :
锁死数据,有了版本号的存在,同一个时刻,只能有一个线程在操作 zookeeper 数据,其他的线程全部操作失败,从而达到支持并发修改操作的目的。 - 版本号 -1 的作用 :
1 ,忽略其他版本号,修改最新版本。
2 ,解锁数据,我不管别的线程在干嘛,我就要修改,说什么都不听,我就要改。 - 用版本号 -1 做修改操作 :12 个线程全成功,不报错
public static void main(String[] args) throws Exception {
for (int i = 1; i <=12 ; i++) {
final int j=i;
Thread t = new Thread(new Runnable() {
public void run() {
try {
ZooKeeper zk = new ZooKeeper("node01:2181", 5000, null);
zk.setData("/a", "aa".getBytes(), -1);
System.out.println(j);
zk.close();
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
t.start();
}
}
10,结论 :
修改操作,单线程操作的话,就用 -1 版本号。
如果考虑并发安全问题,就要用到自己查询的版本号。
14,理论 2 – 权限 : 创建节点时用到 ( 谁可以访问这个节点 )
@Test // set /a jerry
public void create() throws IOException, InterruptedException, KeeperException {
ZooKeeper zk = new ZooKeeper("node01:2181",5000,null);
zk.create("/b","bb".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
zk.close();
}
- OPEN_ACL_UNSAFE :开放权限,所有人都可读,可写
- CREATOR_ALL_ACL : 只有创建这个节点的用户,才能访问这个节点
- READ_ACL_UNSAFE :所有用户都可以读这个节点
15,理论 3 – 节点类型 : 创建节点时用到
- PERSISTENT :永久节点,创建后就一直存在,zk 重启,节点还在
- EPHEMERAL :临时节点,客户端断开后,节点消失 ( 打断点,试试看 )
- PERSISTENT_SEQUENTIAL :永久序列节点
- EPHEMERAL_SEQUENTIAL :临时序列节点
16 ,临时节点测试 : 打断点
- 创建临时节点,打断点 ,执行 :
- 查看这个节点 :看到临时节点
- 放开 debug :
- 再次查看 :临时节点消失
- 作用 :保存临时数据
17 ,序列节点 : 就是一串数字
- 创建后,他会在节点名字后面加一串数字,10 个数字。
- 再次创建序列节点,又一串数字,并且这个数字是刚才的数字加一。
- 重要用途 :同步,锁。
- 类型:永久型序列节点,临时型序列节点。
- 看图,一看便知 :
最后
以上就是舒服店员最近收集整理的关于7 ,javaAPI 使用的全部内容,更多相关7内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复