作者:林冠宏 / 指尖下的幽灵

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

博客:http://www.cnblogs.com/linguanh/

GitHub : https://github.com/af913337456/

腾讯云专栏: https://cloud.tencent.com/developer/user/1148436/activities

虫洞区块链专栏:https://www.chongdongshequ.com/article/1536563643883.html


前序

距离上次择文发表,两月余久。2018年也即将要结束了,目前的工作依然是与区块链应用相关的,也很荣幸在9月初受邀签约出版暂名为《区块链以太坊DApp实战开发》一书,预计在明年年初出版。

这次让我有感记录这篇文章的原因是最近在使用Go语言重写一个原来由PHP语言编写的交易所订单撮合模块的时候,发现订单撮合的部分代码在撮合的时候,为保证各表数据在并发情况下不出现读写脏乱而采用了全局锁表的操作。后面我采用了共享锁的形式进行了修改,于刚刚重写完,并进行了并发单元测试,表现正常。

目录

  • 场景描述
  • 解决问题
  • 订单撮合实例
  • 共享锁 与 排他锁
    • 前置知识
    • 行锁与表锁
    • 两种行锁的特点
    • 两种行锁的加锁方式
    • 锁的释放
    • 操作例子
  • 改造代码片段

场景描述

高并发的业务常见是有很多种类的,最常见的例如秒杀抢购。它们都有一个共同的特点就是数据更新都比较频繁,通常涉及到多张业务表的增改操作,且表格越多的,要考虑的问题也越多。

订单撮合可以理解为订单买卖,拿这个为例子进行列举一个可能会导致数据错乱的情形。假设现在买卖手机,A用户是要买手机的,B用户是卖手机的。A的买入单订单1,和B的卖出单订单2,订单2卖出手机,一台手机卖1000元。此时A的网上的钱包余额是1001元,刚好比手机价格高,是可以成交的。

此时记录用户钱包钱数数量的是一张数据表。每次花费了钱或者增加了钱,都要更新这个表。

当这两笔订单进入到系统里面进行撮合。假设系统的订单撮合运行流程如下图所示:

当判断条件进行A用户的钱包余额判断的时候,发现 1001 > 1000,结果是通过,此时准备进入“进行记录更细”步骤。但是,就在这个过程之中的时间差中,A用户使用了系统的网上提现功能,并成功转出了10元,剩余的是1001 - 10 = 991元。但是由于撮合系统的余额判断过程以及通过了,导致下面的交易流程依然能进行,最终A用991元买了B的1000元售价的手机。

解决问题

上述的常见问题是一个很简单的模型,现实的系统中往往是更复杂的。但是它所体现出的问题却是真实存在的,对于这类问题,有很多解决方案。其中,就可以考虑使用数据库的锁。

本文要介绍的是MySQL数据库的共享锁 与 排他锁,其它的不作说明或引申。

订单撮合实例

下面的截图就是我所重写好的撮合系统原始的PHP代码,所使用了表锁的方式来解决前面的并发读写导致数据脏乱的问题。这种方式虽然是解决了问题,但是导致了性能低下的问题。

共享锁 与 排他锁

前置知识:

  • MySQL 是数据库,不是数据库引擎
  • MySQL有两种常用存储引擎: MyISAM和InnoDB
  • MyISAM不支持事务操作,InnoDB支持事务操作
  • MySQL 的锁分有 行锁 和 表锁
  • MyISAM 只有表锁
  • Innodb 行锁,表锁都有
  • 行锁中有共享锁和排他锁
  • 共享锁 简称 S锁,排他锁简称 X锁

行锁与表锁

简述:

  • 行锁,锁的是表中对应的行,只限制当前行的读写。

  • 表锁,锁的是整张表,限制的是整张表的数据读写。

比较:

  • 行锁,计算机资源开销大,加锁慢;会出现死锁;锁定粒度最小,锁冲突的概率最低,并发度最高,性能高。
  • 表锁,计算机资源开销小,加锁快;不会出现死锁;锁定粒度大,锁冲突的概率最高,并发度最低,性能低。

两种行锁的特点

共享锁

A 对数据 B 加了 共享锁,A能读取和修改数据B,C 等其它只能读取数据B,但是不能修改。直至A释放了B的锁。

排他锁

A 对数据 B 加了 排他锁,A能读取和修改数据B,C 等其它不能再对数据B加其它的锁。直观体验是不能修改,不能使用含有加锁动作的select读取。

两种行锁的加锁方式

要注意的是:

  • 行锁的实现SQL语句中必须要有索引的限制条件,例如含有 where id=xxx 这类语句。
  • 行锁的实现SQL语句没有索引限制条件会变成表锁
  • InnoDB引擎 默认的修改数据类SQL语句,update,delete,insert等,都会自动给涉及到的数据加上排他锁。

共享锁

  • select 的添加可以使用满足格式:select ... where 索引限制 lock in share mode 的语句。例如“select name from lgh_user where id = 1 lock in share model” 此时 id 是索引。

排他锁

  • 满足格式:select ... where 索引限制 for update 的语句

锁的释放

  • 非事务(Transaction) 中,语句执行完毕,便释放锁。

  • 行锁在事务 (Transaction) 中,只有等到当前的事务Transaction 进行了 commit 或 roll back,锁才能释放。

操作例子

演示事务 tx 中的例子,文字解析见图。

改造代码片段

撮合中的所有表锁替换成了共享锁,运行其它业务读取所锁的行数据,在当前事务的批量操作还没结束之前,不允许修改。

完

MySQL 在高并发下的 订单撮合 系统使用 共享锁 与 排他锁 保证数据一致性的更多相关文章

  1. 【mysql】mysql增加version字段实现乐观锁,实现高并发下的订单库存的并发控制,通过开启多线程同时处理模拟多个请求同时到达的情况 + 同一事务中使用多个乐观锁的情况处理

    mysql增加version字段实现乐观锁,实现高并发下的订单库存的并发控制,通过开启多线程同时处理模拟多个请求同时到达的情况 ==================================== ...

  2. Mysql共享锁、排他锁、悲观锁、乐观锁及其使用场景

    一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁定一行) |--共享锁(S锁,MyISAM 叫做读锁) |--排他锁(X锁,MyISAM 叫做写锁) |--悲观锁( ...

  3. [转]MySQL中乐观锁、悲观锁(共享锁、排他锁)简介

    InnoDB与MyISAM Mysql 在5.5之前默认使用 MyISAM 存储引擎,之后使用 InnoDB. MyISAM 操作数据都是使用的表锁,你更新一条记录就要锁整个表,导致性能较低,并发不高 ...

  4. 浅谈Mysql共享锁、排他锁、悲观锁、乐观锁及其使用场景

    浅谈Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景   Mysql共享锁.排他锁.悲观锁.乐观锁及其使用场景 一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁 ...

  5. Mysql共享锁、排他锁、悲观锁、乐观锁

    一.相关名词 |--表级锁(锁定整个表) |--页级锁(锁定一页) |--行级锁(锁定一行) |--共享锁(S锁,MyISAM 叫做读锁) |--排他锁(X锁,MyISAM 叫做写锁) |--间隙锁( ...

  6. (8)MySQL进阶篇SQL优化(InnoDB锁-共享锁、排他锁与意向锁)

    1.锁的分类 锁(Locking)是数据库在并发访问时保证数据一致性和完整性的主要机制.之前MyISAM锁章节已经讲过锁分类,而InnoDB锁按照粒度分为锁定整个表的表级锁(table-level l ...

  7. [数据库事务与锁]详解六: MySQL中的共享锁与排他锁

    注明: 本文转载自http://www.hollischuang.com/archives/923 在MySQL中的行级锁,表级锁,页级锁中介绍过,行级锁是Mysql中锁定粒度最细的一种锁,行级锁能大 ...

  8. mysql共享锁与排他锁

    mysql锁机制分为表级锁和行级锁,本文就和大家分享一下我对mysql中行级锁中的共享锁与排他锁进行分享交流. 共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能 ...

  9. 【数据库】MySQL中的共享锁与排他锁

    转载:http://www.hollischuang.com/archives/923 在MySQL中的行级锁,表级锁,页级锁中介绍过,行级锁是Mysql中锁定粒度最细的一种锁,行级锁能大大减少数据库 ...

随机推荐

  1. REST风格的增删改查(1)

    一.RESTFUL风格的CRUD(增删改查)案例 1.需求: ①显示所有员工信息:URI:emps,请求方式:GET ②添加员工所有信息:显示添加页面:URI:emp,请求方式:GET, 添加员工信息 ...

  2. CentOS下双网卡双IP不同IP段配置

    环境: eth0:10.0.7.2  gw :10.0.7.254 netmask:255.255.255.0 eth1:168.6.101.2    gw :168.6.101.254    net ...

  3. linux 新建用户、用户组 以及为新用户分配权限(转)

    本文转自https://www.cnblogs.com/clicli/p/5943788.html 感谢作者 Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先 ...

  4. Android如何实现茄子快传

    Android如何实现茄子快传茄子快传是一款文件传输应用,相信大家都很熟悉这款应用,应该很多人用过用来文件的传输.它有两个核心的功能: 端到端的文件传输Web端的文件传输这两个核心的功能我们具体来分析 ...

  5. 异常 Exception 知识点总结 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. 解析XML出错,无法创建DOMDocument对象

    [问题] 加载XML配置文件时,创建DOMDocument对象总是失败,创建代码如下: MSXML2::IXMLDOMDocumentPtr pXMLDoc; MSXML2::IXMLDOMEleme ...

  7. 【Boost】boost::string_algo详解2——find相关函数

    来自: https://blog.csdn.net/huang_xw/article/details/8276123 函数声明:   template<typename Range1T, typ ...

  8. 分享12款令人瞠目结舌的WebVR演示和实验效果

    不管你信不信, WebVR绝对是浏览器下一个让你激动的技术方向, 也许很快你就可以使用VR头显或者相关设备直接访问web内容和资源啦! 在这篇资源分享帖中,我们将介绍很多基于浏览器的VR演示和游戏,帮 ...

  9. 【网络安全】SSLSplit实现中间人攻击

    中间人攻击,即在中间监听获取网络数据以便获取的有价值的信息实现攻击破坏的目的,即client-mid man-server,此处介绍的sslsplit可以作为mid man监听ssl信息及HTTP信息 ...

  10. jquery中选择器input:hidden和input[type=hidden]的区别

    关于选择器:hidden的说明,在jquery说明文档中是这样说的:匹配所有不可见元素,或者type为hidden的元素.而[type=hidden]是查找所有type属性等于hidden的元素.两者 ...