分布式锁与分布式事务的理解

一、什么是分布式锁,  什么是分布式事务?

      1.1、 分布式锁:  多进程的并发问题(传统的单体系统中我们可以用Synchronized、Lock等方式保证数据的安全,多进程中这个无效)

      1.2、 分布式事务:多进程的事务管理,解决的是跨进程会话数据的一致性问题(传统我们可以利用事务管理,复合操作要么全部成功要么全部失效,分布式中事务无法直接跨进程进行回滚)

 

二、分布式锁和分布式事务的应用场景

       2.1、分布式锁:秒杀活动,我们如何防止超卖现象。

       2.2、 分布式事务: 跨进程操作中我们要防止会话中某一个或者几个操作失败,确保不产生脏数据。

三、分布式锁与分布式事务的解决方案

 

      3.1、分布式锁

                3.1.1、数据库(以MySQL举例)

                           获取锁:因为对表中字段name做了唯一性约束,这里如果有多个请求同时提交到数据库的话,数据库会保证只有一个操作可以成功。

                           释放锁:删除/修改当前的数据

                              

CREATE TABLE `lock`  (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL 
   DEFAULT '' COMMENT '锁定的方法名',

  `desc` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL
   DEFAULT '备注信息' COMMENT '备注信息',

  `update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 
   CURRENT_TIMESTAMP(0) COMMENT '保存数据时间,自动生成',

   PRIMARY KEY (`id`) USING BTREE,

   UNIQUE INDEX `uidx_name`(`name`) USING BTREE

)  ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

                        

                3.1.2、Redis

                                  Redis主要是利用Redis的单线程进行特性实现分布式锁,

    /*
     * key :产品Id
     * 
     * value:一个唯一的时间戳
     /

    //获取锁
    public boolean requireLock(String key, String value) {
        
        if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
            return true;
        }


        Object current_value = redisTemplate.opsForValue().get(key);

        if (!StringUtils.ObjectToString(current_value).equals("") && 
            Long.parseLong(current_value.toString()) < System.currentTimeMillis()) {

            String old_value = 
                            redisTemplate.opsForValue().getAndSet(key,value).toString();

            if (!StringUtils.ObjectToString(old_value).equals("") && 
                old_value.equals(current_value)) {
                return true;
            }
        }
        return false;
    }


  //线程解锁,删除key
  public void unlock(String key, String value) {
     if(StringUtils.ObjectToString(redisTemplate.opsForValue().get(key)).equals(value)) {
               redisTemplate.opsForValue().getOperations().delete(key);
        }

  }


  private RedisTemplate redisTemplate;

    public RedisLock(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
  }

 

 

 

                3.1.3、Zookeeper

                        实现分布式锁的原理: 1.1、利用zookeeper树形结点的特性, 一个结点只能下面唯一的临时结点,唯一性。 1.2、唯一结点的有序性,顺序为 从小到大。 1.3、watch监控机制,当结点删除的时候会发送了一个通知



//Zookeepr实现分布式锁
public class CustomizedZKLock extends ReentrantLock {

    private ZookeeperUtils zkUtils;
    private String lockNodeName;
    private String lockPath = "/lock";
    private String lockStr = "lock0";
    private CountDownLatch countDownLatch;

    public CustomizedZKLock(String zkConnectStr, String lockStr) {
        if (lockStr != null) {
            this.lockStr = lockStr;
        }
        try {
            zkUtils = new ZookeeperUtils(zkConnectStr);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public CustomizedZKLock(String zkConnectStr) {
        this(zkConnectStr, null);
    }

    //所有的线程在进行获取锁
    @Override
    public void lock() {
        super.lock();
        countDownLatch = new CountDownLatch(1);
        //在zk中创建临时有序节点
        lockNodeName = zkUtils.createZNodeES(lockPath, "/" + lockStr, this::tryGetLock);
        //阻塞等待获取资源
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //当zk节点变动时尝试获取锁
    private void tryGetLock(WatchedEvent watchedEvent) {
        if (tryGetLock()) {
            countDownLatch.countDown();
        }
    }

    private boolean tryGetLock() {
        List<String> list = zkUtils.getChildNode(lockPath);
        list.sort(String::compareTo);
        list = list.stream().
                filter(s -> s.startsWith(lockStr)).collect(Collectors.toList());

        //如果获取到锁
        if (lockNodeName.equals(lockPath + "/" + list.get(0))) {
            return true;
        }
        return false;
    }

    @Override
    public void unlock() {
        //释放锁并删除zk节点
        zkUtils.deleteNode(lockNodeName);
        zkUtils.close();
        super.unlock();
    }
}


//系统工具类

public class ZookeeperUtils {

    private ZooKeeper zookeeper;
   
    public ZookeeperUtils(String zkConnectStr) throws IOException
    {
        zookeeper = new ZooKeeper(zkConnectStr, 2000, null);
    }

    /**
     * 创建临时有序节点
     */
    public String createZNodeES(String path, String node, Watcher watch) {
       
 try {
            watch(path, watch);
            return zookeeper.create(path + node,new byte[1], ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 对某个节点添加监控
     * @param path
     * @param watcher
     */
    private void watch(String path,Watcher watcher) {
        try {
               zookeeper.getChildren(path, e -> {
                watcher.process(e);
                watch(path,watcher);
            });
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭连接
     */
    public void close() {
        try {
            zookeeper.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取子节点列表
     * @return
     */
    public List<String> getChildNode(String parentPath) {
        try {
            return zookeeper.getChildren(parentPath, true);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 删除节点
     * @param znodePath 要删除的节点路径
     */
    public void deleteNode(String znodePath) {
        try {
            zookeeper.delete(znodePath,-1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }
}




//系统测试类

public class Main {
    public static void main(String[] args) throws InterruptedException {
        CustomizedZKLock zkLock = new CustomizedZKLock("172.16.104.1:2181");
        zkLock.lock();
        System.out.println("获得锁");
        Thread.sleep(10000);
        zkLock.unlock();
        System.out.println("释放锁");
    }
}

 

      3.2、分布式事务

                 3.2.1、2PC理论以及消息通知机制

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值