专栏首页Java编程技术谈谈幂等技术(二)

谈谈幂等技术(二)

一、前言

前面我们讨论了《如何基于幂等表实现幂等处理》,本文我们就来看看如何基于乐观锁、悲观锁来做幂等处理。

二、基于数据库乐观锁进行幂等处理

首先我们看如何采用数据库的行锁+乐观锁来实现幂等。

在mysql Innodb存储引擎里面实现了行锁功能,当我们根据id去更新记录时就会获取到行锁。多个线程根据同一个记录id去更新行记录时只有一个线程可以获取到锁,其他线程会阻塞。

乐观锁的实现方式常见有两种:

  • 在业务表里面添加一个version版本字段
  • 使用业务表里面自带的状态机字段 比如订单流程,每个订单状态有:创建->支付->发货->验货等等。但是需要注意状态机不能出现回路,因为这会导致ABA问题。

上面两种方式本质一样,不同在于如果业务表里面自带的状态机字段,那么我们就不必额外加一个version字段了。下面我们统一称version和状态字段为幂等字段。

基于乐观锁实现幂等流程:

  • 根据select ... from biz_table where id = #id and 幂等字段=幂等字段值拿到DO对象
  • 根据DO对象进行处理:可能是修改DO对象里面的某些值
  • 进行乐观锁幂等:update biz_table set 幂等字段=新幂等值... where id = #id and 幂等字段= #DO对象.幂等字段;

如果使用version作为幂等处理字段,则上面第三步可以修改为: update biz_table set version=version+1... where id = #id and version= #DO对象.version;

如果使用业务状态作为幂等处理字段,则上面第三步可以修改为: update biz_table set 状态字段=状态机的下一个状态... where id = #id and 状态字段= #DO对象.状态字段;

可知基于乐观锁时,我们基于第三步做幂等处理。当多个相同id的请求同时(并发)或者先后(顺序)过来后,第一和第二步可能是并发或者顺序执行,但是第三步只有一个请求会返回1,其他都返回0,这就实现了幂等处理.

需要注意的是乐观锁方式在下面这种场景才用(以基于版本方案实现乐观锁为例):

image.png

也就是服务B内可以实现幂等处理前提是,调用方A把记录行id和行记录对应的版本号以参数形式传递过来了。

如下时序图中,服务A调用服务B时候如果只是把记录id传递给服务B,则当服务A顺序多次以相同记录id调用服务B时候,服务B是实现不了幂等的(因为多次调用时步骤2,3,4都会被执行)。

image.png

三、基于数据库悲观锁进行幂等处理

恕我直言,基于悲观锁实现不了通用的幂等处理,为何那?且让我们一一道来。

我们且来回忆一下幂等技术用来保证唯一性,就是相同参数的多次请求和一次请求对业务效果都一样。

而悲观锁处理流程一般为:

  • 开启事务
  • select ...from biz_table where id = #id for update 对行记录加锁,并返回DO对象
  • 对DO对象进行处理
  • update biz_table set ... where id = #id
  • 提交或者回滚事务

那么当多个id一样的请求顺序或者并行过来后,会导致上面五个步骤都执行(虽然并发过来时候,可能多个请求会暂时hold到步骤2),如果步骤三本身不是幂等的,那么这就起不到幂等作用了。

四、总结

这里我们补充下,幂等技术不是简单的对N多相同请求参数的请求,只处理其中一个,其他的请求忽略,直接返回。而是要保证即使这N多请求都处理了,但是处理的结果的效果和一次处理结果一样,所谓处理结果是指对业务的影响。

本节讲解的乐观锁方式相比基于幂等表方式,对业务入侵比较大,需要在业务表添加一个版本字段或者强依赖业务状态字段。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java并发编程之美-双11限时五折优惠

    天猫链接:https://detail.tmall.com/item.htm?spm=a220m.1000858.1000725.61.59a73c85cVE3...

    加多
  • 分布式事务- TCC编程式模式

    严格遵守ACID的分布式事务我们称为刚性事务,而遵循BASE理论(基本可用:在故障出现时保证核心功能可用,软状态:允许中间状态出现,最终一致性:不要求分布式事务...

    加多
  • 亲缘性线程池,这是什么鬼?

    JDK中的线程池固然好,但是其不具有亲缘性,也就是当我们顺序向其中投递多个任务后,不能保证具有相同属性的任务顺序执行,本文我们就来看一个可以实现亲缘性的线程池。

    加多
  • SQL Server为啥使用了这么多内存?

    原文地址:http://support.microsoft.com/gp/anxin_techtip6/zh-cn

    Edison Zhou
  • 面试题|无索引如何删除亿级数据?

    存在索引的情况下就比较简单,直接利用索引进行删除,写一个for 循环语句 每次删除500行,每次判断delete 影响的行数可以累加计算删除了多少行,直到删除结...

    用户1278550
  • python中查看变量内存地址的方法

    本文实例讲述了python中查看变量内存地址的方法。分享给大家供大家参考。具体实现方法如下:

    py3study
  • Mybatis系列第7篇:各种查询详解

    Mybatis系列目标:从入门开始开始掌握一个高级开发所需要的Mybatis技能。

    路人甲Java
  • 浅谈python中的多线程和多进程(二)

    前文《浅谈python中的多线程和多进程》中我们分享过一个例子,就是分别利用python中的多线程和多进程来解决高运算量的任务,从中看出二者的一些区别。其中一点...

    一只羊
  • pt-osc在线重建表导致死锁的分析及对应的优化方案

    在业务低峰通过pt-osc在线做DDL期间出现死锁,导致业务的SQL被回滚了,对应用不友好。 本案例死锁发生的场景:pt-osc拷贝最后一个chunk-siz...

    老叶茶馆
  • 约束

    一 介绍 约束条件与数据类型的宽度一样,都是可选参数 作用:用于保证数据的完整性和一致性 主要分为: PRIMARY KEY (PK) 标识该字段为该表的...

    用户1214487

扫码关注云+社区

领取腾讯云代金券