• Redis(六)——Redis6的事务和锁机制(未完成,待补)


    目录

    基本操作

    事务冲突

    悲观锁

    乐观锁

    演示乐观锁和事务特性

    Redis事务三特性

    秒杀案例

    超卖和超时问题

    库存遗留问题


    基本操作

            Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

    Redis事务的主要作用就是串联多个命令防止别的命令插队。

            从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,只是放在队列中等待执行,直到输入Exec后,Redis会将之前的命令队列中的命令依次执行。组队的过程中可以通过discard放弃组队。 

    事务的错误处理(两种方式)

    组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消。

     组队阶段报错,提交失败

    如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。

    组队成功,提交有成功有失败情况 

    (一個編譯錯誤 一個運行錯誤 ?)

    事务冲突

    事务冲突问题,多个人同时操作这10000块钱:

    悲观锁

            悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁表锁等,读锁写锁等,都是在做操作之前先上锁。

            我拿到了10000块钱,先给他上锁,这样别人就无法操作这10000块钱了,只能看着我操作,当我减去8000块钱的时候,还剩下2000,这个过程block中别人不能操作,变成2000块钱之后就把它解锁,解锁之后别人就能拿到这2000进行操作,当别人拿到这两千的时候就会上锁,想减去5000,现两千块钱不够,最终不能操作。

            每次操作之前先上锁,当操作完之后再解锁,别人才能够操作,这种方式就叫做悲观锁方式,这种方式的缺点是效率低,只能单人操作。

    乐观锁

            乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量Redis就是利用这种check-and-set机制实现事务的。

             我们在数据操作的时候,给数据加上一个字段叫做版本号表示数据版本,假如10000第一次的版本号是1.0,此时所有人都能得到这个版本的数据,这个数据的版本都是1.0(第一个人和第二个人都得到10000的数据,他们的版本都是1.0),第一个人比较快,减了8000块钱,最终就变为2000,如果数据改变的话,在改的时候它会自我操作,除了植被更改以外,它的版本号也同步进行更新,之前是1.0,当变为2000的时候就变为了1.1。此时第二个人拿着数据,就会检查当前数据的版本号跟数据库当中的版本号是否一致,因为数据库当中的版本号已经改为了1.1,而第二个人拿到的数据版本号还是之前的1.0,两个版本号相比较发现并不一样,如果不一致的话,那么就不能够继续操作

            抢票就是乐观锁典型的应用场景,比如在系统中只有一张票了,同时有很多人都去抢这张票,所有人都能去抢这张票,但只有一个人才能支付成功。

    演示乐观锁和事务特性

    WATCH key [key ...]

            在执行multi之前,先执行watch key1 [key2],可以监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

    • 在两个客户端添加监视:

    • 在两个客户端开启事务操作:

    • 在两个客户端分别改变balance的值:

    在第一个客户端当中加10

    在第二个客户端当中加20

     1中执行成功

    2中执行失败

            AB同时判断version成功,谁先事务中赋值exec成功,未赋值的就会失败。

           unwatch取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后,EXEC 命令或DISCARD 命令先被执行了的话,那么就不需要再执行UNWATCH 了。

    Redis事务三特性

    • 单独的隔离操作

            事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

    • 没有隔离级别的概念

            队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行。

    • 不保证原子性

            事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚(如果在组队中命令没有失败,在提交过程中失败的那个命令失败,而其他的正常执行)。

    秒杀案例

            假如我现在拿出来十个商品进行秒杀,假如有100个人参与,假如100个人当中有一个人抢到了商品,那么商品库存就要减1变成9,然后这个抢到商品的用户就要添加到秒杀成功者清单当中,以此类推。

    Servlet: 

    1. public class SecKillServlet extends HttpServlet {
    2. private static final long serialVersionUID = 1L;
    3. public SecKillServlet() {
    4. super();
    5. }
    6. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    7. String userid = new Random().nextInt(50000) +"" ;
    8. String prodid =request.getParameter("prodid");
    9. //boolean isSuccess=SecKill_redis.doSecKill(userid,prodid);
    10. boolean isSuccess= SecKill_redisByScript.doSecKill(userid,prodid);
    11. response.getWriter().print(isSuccess);
    12. }
    13. }

            通过随机数生成用户ID,然后得到传过来的商品ID,然后调用秒杀方法, 判断成功或者失败,核心就是秒杀过程。

    秒杀方法(基本实现):

    1. package com.atguigu;
    2. import java.io.IOException;
    3. import java.util.HashSet;
    4. import java.util.List;
    5. import java.util.Set;
    6. import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    7. import org.slf4j.LoggerFactory;
    8. import ch.qos.logback.core.rolling.helper.IntegerTokenConverter;
    9. import redis.clients.jedis.HostAndPort;
    10. import redis.clients.jedis.Jedis;
    11. import redis.clients.jedis.JedisCluster;
    12. import redis.clients.jedis.JedisPool;
    13. import redis.clients.jedis.JedisPoolConfig;
    14. import redis.clients.jedis.ShardedJedisPool;
    15. import redis.clients.jedis.Transaction;
    16. /**
    17. *秒杀方法
    18. */
    19. public class SecKill_redis {
    20. public static void main(String[] args) {
    21. Jedis jedis =new Jedis("192.168.x.xxx",6379);
    22. System.out.println(jedis.ping());
    23. jedis.close();
    24. }
    25. //秒杀过程
    26. public static boolean doSecKill(String uid,String prodid) throws IOException {
    27. //1 uid和prodid非空判断
    28. if(uid == null || prodid == null) {
    29. return false;
    30. }
    31. //2 连接redis
    32. Jedis jedis = new Jedis("192.168.x.xxx",6379);
    33. //3 拼接key
    34. // 3.1 库存key
    35. String kcKey = "sk:"+prodid+":qt";
    36. // 3.2 秒杀成功用户key
    37. String userKey = "sk:"+prodid+":user";
    38. //4 获取库存,如果库存null,秒杀还没有开始
    39. String kc = jedis.get(kcKey);
    40. if(kc == null) {
    41. System.out.println("秒杀还没有开始,请等待");
    42. jedis.close();
    43. return false;
    44. }
    45. // 5 判断用户是否重复秒杀操作
    46. if(jedis.sismember(userKey, uid)) {
    47. System.out.println("已经秒杀成功了,不能重复秒杀");
    48. jedis.close();
    49. return false;
    50. }
    51. //6 判断如果商品数量,库存数量小于1,秒杀结束
    52. if(Integer.parseInt(kc)<=0) {
    53. System.out.println("秒杀已经结束了");
    54. jedis.close();
    55. return false;
    56. }
    57. //7.1 库存-1
    58. jedis.decr(kcKey);
    59. //7.2 把秒杀成功用户添加清单里面
    60. jedis.sadd(userKey,uid);
    61. System.out.println("秒杀成功了..");
    62. jedis.close();
    63. return true;
    64. }
    65. }

    ab工具模拟高并发

    在linux中 yum install httpd-tools 命令安装

    -n:请求数量

    -c:请求中的并发数量

    -p:提交的参数(POST提交)

    -T:参数类型

    vim postfile 模拟表单提交参数,以&符号结尾;存放当前目录。

    内容:prodid=0101&

    ab -n 1000 -c 100 -k -p ~/postfile -T application/x-www-form-urlencoded http://192.168.x.xxx:8081/Seckill/doseckill

    模拟并发

    两个问题:

    redis中的数据:

    两个问题:

    • 连接超时

            当请求过多时,redis无法处理这么多请求,有的请求不能处理,就需要等待,如果等待的时间过长,还没有连接上就会超时。

    • 超卖

            商品已经秒杀完成了,但是还提示秒杀成功。

     26-事务和锁机制-秒杀案例-超卖和超时问题解决_哔哩哔哩_bilibili

    超卖和超时问题

    库存遗留问题

  • 相关阅读:
    android studio 编译Telegram源码经验总结(2023-11-05)
    使用Visual Studio分析.NET Dump
    Vue 3.0 全家桶 + Vite 从零配置开发环境、生产环境
    C++核心编程(三十三)容器(list)
    大疆智图(PC):新一代高效率高精度摄影测量软件
    GIT简单使用
    Vue Chrome浏览器手动调节模拟网速
    VMware安装Ubuntu 16.04(完整版图文教程)
    Linux安全之iptables黑白名单
    基于51单片机的波形发生器proteus仿真数码管LCD12864显示
  • 原文地址:https://blog.csdn.net/m0_52601969/article/details/126256623