zookeeper

[ZooKeeper之八] ZooKeeper 事务

2020-06-13  本文已影响0人  小胡_鸭

  有的时候,我们希望 ZooKeeper 在执行多个操作时,要么全部成功,要么全部失败,把这多个操作看成一个原子性操作,这通常是为了解决在多线程环境中为了避免竞态条件导致的问题。

  ZooKeeper 从3.4.0开始提供了multiop的特性,支持原子性地执行多个操作,基于multiop封装了事务对象 Transaction,使用形式更加灵活方便。

一、multiop

  multiop使用步骤:
(1)创建 Op 对象,通过调用 Op 类的静态方法来 create(创建)、delete(删除)、getData(获取节点数据)并返回 Op 对象;
(2)将代表多个操作的多个 Op 对象以 Iterable 集合的形式传参给 ZooKeeper 的 multi 方法调用。

调用形式如下:

public List<OpResult> multi(Iterable<Op> ops) throws InterruptedException, KeeperException;

  下面演示同时删除 /a/a/b 节点为例演示multiop的使用,操作结果只可能是全部成功或全部失败,不存在一个成功一个失败的情况,代码如下:

    Op deleteZnode(String z) {
        return Op.delete(z, -1);
    }
    
    // 同步版本
    void testMultiop() throws InterruptedException, KeeperException {
        List<OpResult> results = zk.multi(Arrays.asList(deleteZnode("/a/b"), deleteZnode("/a")));
        for (OpResult result : results) {
            if (result instanceof DeleteResult) {
                System.out.println("delete success");
                DeleteResult dresult = (DeleteResult) result;
                System.out.println(dresult.hashCode());
            }           
        }
    }

  假如 ZooKeeper 数据中存在 /a/a/b 节点,则都能删除成功。



  假如只存在 /a,执行时会抛出 NoNodeException 因为不存在 /a/b,执行完之后发生 /a 还在。
执行multiop之前

执行multiop之后
  跟 ZooKeeper 的其他节点操作一样,multiop也提供了异步的版本,通过返回码判断执行结果,不用去捕获处理异常,调用形式如下:
public void multi(Iterable<Op> ops, MultiCallback cb, Object ctx);

  将上面的同步代码修改成异步的形式,代码如下:

    // 异步版本
    void asynTestMultiop() {
        zk.multi(Arrays.asList(deleteZnode("/a/b"), deleteZnode("/a")), cb, Arrays.asList(deleteZnode("/a/b"), deleteZnode("/a")));
    }
    
    MultiCallback cb = new MultiCallback() {        
        @Override
        public void processResult(int rc, String path, Object ctx, List<OpResult> opResults) {
            switch (Code.get(rc)) {
                case CONNECTIONLOSS:
                    asynTestMultiop();
                    break;
    
                case NONODE:
                    System.out.println("NoNode Error!");
                    break;
                    
                default:
                    System.out.println("Error when trying to delete node: " + KeeperException.create(Code.get(rc), path));
            }
        }
    };


二、Transaction

  ZooKeeper 的 Transaction 封装了multi,使用上更加灵活,在提交执行之前可以随时在原子操作中增加新的操作,还可以跨方法执行事务,commit 方法同样提供了同步和异步两种形式。

  演示 Transacion 同步提交事务:

    void transactionTest() throws InterruptedException, KeeperException {
        Transaction t = zk.transaction();
        t.delete("/a/b", -1);
        t.delete("/a", -1);
        List<OpResult> results = t.commit();
        for (OpResult result : results) {
            if (result instanceof DeleteResult) {
                System.out.println("delete success");
            }           
        }       
    }

  演示 Transacion 跨方法异步提交事务:

    void AsyncTransactionTest() {
        Transaction t = zk.transaction();
        t.delete("/a/b", -1);
        anotherFunc(t);
    }
    
    void anotherFunc(Transaction t) {
        t.delete("/a", -1);
        t.commit(cb, null);
    }
上一篇 下一篇

猜你喜欢

热点阅读