zoukankan      html  css  js  c++  java
  • redis竞汰数据同步问题解决

    Java面试题 Part11 乐观锁与悲观锁

    Redis

    面试的时候遇到过问Redis是如何解决“竞态条件”的,相关知识点总结一下。

    乐观锁

    所谓竞态条件,举个例子,一个代表点击数的数值hitcount,每个客户点击一次则+1。

    没有事务的时候,假设我们的操作如下:

    hc=GET hitcount;

    hc=hc+1;

    SET hitcount $hc;

    非并发状态下,这样做是OK的,但是并发状态下会出现的问题是:

    Java面试题 Part11 乐观锁与悲观锁

    1

    A和B两个客户端分别从Redis处取值,并+1,值都是11。

    Java面试题 Part11 乐观锁与悲观锁

    2

    Redis是单线程模型,所以A和B的SET命令只能先执行1个,此处先执行A,hitcount更新为11。

    Java面试题 Part11 乐观锁与悲观锁

    3

    接着执行B的SET命令,hitcount依然是11,这就是明显的因为竞态而产生的错误,hitcount应该为12才是。

    Redis的事务其实是通过MULTI命令开启事务,将后续一系列的命令放在一个队列里,不立即执行,直到EXEC命令,队列中的命令才会依次执行。

    命令类似:

    MULTI;

    set val1 111;

    set val2 222;

    EXEC;

    在实际工作中,我们也会经常遇到这种问题:我们必须先拿到数据,根据数据做出判断,进行一些处理之后,再更新数据,这时候我们就没法保证取数据、更新数据在同一个队列事务中了。

    这就需要乐观锁。简单说,我们每取一个数据的时候,Redis不仅返回数值,还会返回这个数值的版本号。

    当我们执行更新命令时,Redis会拿你要SET值的版本号与库里现在值的版本号进行比对,如果相同,则更新,版本号变更。

    如果版本号不同,则说明在我们执行更新命令之前,有其他客户端修改了这条数据,我们的更新操作失败。

    Redis里是通过WATCH命令来监控版本号的。

    WATCH hitcount;

    hc=GET hitcount;

    hc=hc+1;

    MULTI;

    SET hitcount $hc;

    EXEC;

    因为通过WATCH监控了hitcount这个Key,那么在事务中SET的时候,一旦发现版本号不对,执行就失败。

    悲观锁

    乐观锁是CAS——Check And Set,先检查(版本号)再设置更新,那么悲观锁就是先锁,再查,最后更新。

    以MySQL为例,我们要实现悲观锁:

    SELECT * FROM tabA AS t WHERE t.id=1 FOR UPDATE;

    这样,因为主键是明确指定的(id=1),所以这一行记录就被锁定了——行锁定,在本事务被commit之前,这条数据都只会被本事务的SQL语句进行修改,其他事务的加锁操作,更新操作都会在本事务提交之后再执行,单纯的查询则不受影响。

    如果没有指定明确地主键,则锁定的是表——表锁定。

  • 相关阅读:
    深入理解ASP.NET Core依赖注入
    Docker Swarm 从入门到放弃
    Asp.net Core全局异常监控和记录日志
    NServiceBus+RabbitMQ开发分布式应用
    NServiceBus+Saga开发分布式应用
    使用NServiceBus开发分布式应用
    springboot自动配置原理
    SpringMVC 源码解析
    instruments symbol name 不显示函数名!
    ld: framework not found FileProvider for architecture arm64
  • 原文地址:https://www.cnblogs.com/520playboy/p/8481935.html
Copyright © 2011-2022 走看看