• 并发场景下常见的锁及简单使用


    1. MySQL悲观锁

      悲观锁:顾名思义,对待过来的请求持比较悲观的态度,在处理请求的整个过程中,将数据锁定,不允许其他进程/线程 修改

      set autocommit=0;
      begin;
      select * from table where id = xx for update; //互斥锁      //InnoDB 必须明确索引字段的值(查询需走索引),否则会将整个表的数据都加锁
      ......
      // 对数据进行操作
      ......
      commit;
      

      当session1执行完 select * from table where field = xx for update; (field需要是索引字段) 的时候 就将那一行的数据锁定了,此时 session2 再来执行 for update 或者 修改此条数据的操作的时候就会被阻塞

      注:MySQL 悲观锁 虽然数据可以保证绝对正确,但是并发效率极低,一般不使用

    2. MySQL乐观锁

      乐观锁:顾名思义,对待过来的请求持比较乐观的态度,先假设不会冲突,在提交更新的时候再去检验数据有没有被其他进程修改过,如果中间有被其他进程修改过起冲突了,则返回错误

      乐观锁的实现

      1. 版本控制 感兴趣的话可以看一下MySQL的MVCC的实现原理(InnoDB默认的可重复读隔离级别)

        MVCC 原理 大致是这样的:

        1. 数据库有隐藏的创建版本和删除版本的字段,每次开始事务的时候,事务版本号都会自增
        2. 新增数据的时候,在对应的创建版本号的地方填上 当前事务的版本号
        3. 更新数据的时候,将要更新的数据行的删除版本号填上当前事务的版本号,然后插入一条新数据,创建版本号 填上 当前事务的版本号
        4. 删除数据的时候,将要删除的数据行的删除版本号填上当前事务的版本号
        5. 查询数据的时候,查询 删除版本号大于当前事务的版本号 或 创建版本号小于等于当前事务的版本号且删除版本号为空
      2. 在where 条件中进行限制

        // 在秒杀场景中的使用
        1. 将库存字段设置为 unsigned int 类型,库存一直减,减到负数就直接报错,应用程序捕获这个错误进行处理这种方式依赖数据库抛异常,算是数据库设计的一种技巧,不算乐观锁
        2. 更新库存的时候,直接 update table set remain_amount = remain_amount - num where id = xx and remain_amount >= num							// num 是一个
        3. 结合 1,2
        
    3. Redis 分布式锁 参考 石杉的架构笔记--Redis分布式锁的实现原理

      1. 原理大概是这样的(Redis可能是一个集群,这里就当做是单机的场景,集群的话 加锁只给master节点加锁):

        1. Redis 是单进程单线程的,不涉及到锁的问题,至于Redis的并发是借助 I/O多路复用( Epoll)实现
        2. 请求进来后先检查 resource_str 这个hash类型的key存在不,如果不存在,则 hset resource_str client_str 1 ,然后设置一个过期时间;如果resource_str 存在,则 判断 resource_str client_str 存在不,如果存在,延长过期时间;如果不存在则获取一下 resource_str 的过期时间 time,然后client 进入循环等待time 秒 再重新 执行2 这个过程。
        3. 释放锁的时候,直接将 resource_str key 删除即可

        注:1. resource_str代表资源key client_str 代表客户端字符串或者是session字符串
              2. 上述情况如果 time过长,可以直接返回 超时
              3. 在redis master实例宕机的时候,可能导致多个客户端同时完成加锁

    4. Redis 分布式锁的改进

      1. 上述的Redis 分布式锁是基于一个 redis hash key 来实现的,这样相当于串行化,并发效果也不好,在 石杉的架构笔记--分布式锁高并发优化 中提到了一种办法,分段加锁。分段加锁相当于是把之前的一个大锁分成n个小锁,每个小锁管固定的一部分资源。当请求进来的时候就先利用3.1所述的Redis分布式锁原理选一个资源锁给当前客户端加上,然后判断商品库存满不满足,如果满足的话直接进行 创建订单、减库存、释放锁;如果不满足的话,直接释放当前的锁,再给客户端选下一个资源锁加上 (这个选资源锁的过程可以有一个随机的算法,但是需要保证尽量不重复)。当所有的资源锁都不满足的话,就只能返回库存不足了。
      2. 缺点:
        1. 实现比较复杂
        2. 如果每次下单的数量从一开始就一直大于 分段后的资源数,这种情况会到导致商品卖不完

    注:1. 本文根据自己的理解所写,如有不对的地方请及时反馈。
          2. 如需转载,请注明出处:https://www.cnblogs.com/zhuchenglin/p/12694937.html

  • 相关阅读:
    201271050130-滕江南 实验二 个人项目—《西北师范大学学生疫情上报系统》项目报告
    201271050130-滕江南 实验一 软件工程准备—<读《构建之法——现代软件工程》心得体会>
    201271050130-滕江南《面向对象程序设计(java)》课程学习总结
    201271050130-滕江南-《面向对象程序设计(java)》第十七周学习总结
    201271050130-滕江南-《面向对象程序设计(java)》第十六周学习总结
    201271050130-滕江南-《面向对象程序设计(java)》第十五周学习总结
    201271050130-滕江南-《面向对象程序设计(java)》第十四周学习总结
    《男403团队》:线上点餐系统选题报告
    计算机与软件工程作业5
    计算机软件工程作业4
  • 原文地址:https://www.cnblogs.com/zhuchenglin/p/12694937.html
Copyright © 2020-2023  润新知