阿里云产品通用代金券,最高可领1888分享一波阿里云红包. 阿里云的购买入口

为什么要加锁

多核计算机的出现,计算机实现真正并行计算,可以在同一时刻,执行多个任务。在多线程编程中,因为线程执行顺序不可控导致的数据错误。比如,多线程的理想状态是这样的

多线程理想.jpg

但是实际情况是这样的:

多线程实际.jpg

在网络编程中,在同一时刻,多个客户端同时请求同一个资源,如果不做控制,也会带来数据错误。比如在同一时间有10000人去抢10张火车票,10张火车票有可能会买给100个人,这显然是不符合要求的。

在多线程编程中,为了解决线程执行不可控带来的问题,通常情况下都是通过加锁来实现数据同步的。在网络编程中,也可以通过加锁机制来控制。

在网络编程中,可以通过给数据库加锁,达到控制并发的目的。在php开发时,基本都是使用mysql作为数据库。所以,就会给mysql加锁控制网络并发引起数据错误问题。

MySQL的存储引擎

不是要说MySQL的锁吗,怎么说上存储引擎了?因为MySQL存储引擎不同,锁也会不同。MySQL有MyISAM 和InnoDB两种存储引擎,现在主要使用InnoDB,所以主要介绍InnoDB下锁的使用。

InnoDB引擎支持事务操作,使用事务可以保证多条sql语句执行的完整性(要不都成功,要不都失败)

事务是由一组SQL语句组成的逻辑处理单元,事务具有4属性

原子性(Actomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。

一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以操持完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。

隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。

持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

多个事务并发执行会带来新的问题

更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个 事务都不知道其他事务的存在,就会发生丢失更新问题——最后的更新覆盖了其他事务所做的更新。例如,两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改保存其更改副本的编辑人员覆盖另一个编辑人员所做的修改。如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题

脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做“脏读”。

不可重复读(Non-Repeatable Reads):一个事务在读取某些数据已经发生了改变、或某些记录已经被删除了!这种现象叫做“不可重复读”。

幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。

曾经年少无知的我,以为使用事务就能保证并发情况下数据同步问题,后来的一次惨痛经历才明白了,事务不能保证并发情况的数据同步问题,需要事务和锁同时使用才能保证。

锁的种类

乐观锁 机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。相对悲观锁而言,乐观锁更倾向于开发运用。

悲观锁 具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

MySQL中锁的种类

乐观锁和悲观锁是一种思想,不是具体实现,在MySQL中,有锁的具体的实现方式

(文中的线程在MySQL中可以视作MySQL的连接)

共享锁 一个线程在持有锁时,其他的线程可以查询被锁的数据,但是不能修改,不能删除。实现方式

SELECT * FROM table_name WHERE id =? lock in share mode;

排它锁 一个线程在持有锁时,其他的线程不能查询,不能更新,不能删除被锁的数据,直到锁被释放.

SELECT * FROM table_name WHERE id =? for update

总结一下:共享锁类似于java中的读锁,一个线程在持有乐观锁的时候,其他的线程也可以对被锁的数据进行读操作,但是不能对被锁的数据进行删除和更新操作;排他锁类似于java的写锁,一个线程持有写锁的时候,其他的线程不能再对被锁的数据进行任何查询,更新,删除操作。

重点 InnoDB的行锁是基于索引实现的,如果在查询中不使用索引,会锁表。

MySQL锁粒度

表级锁 是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MyISAM与InnoDB都支持表级锁定。表级锁分为表共享读锁与表独占写锁。

行级锁 是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁。

共享锁的使用

注意: 下面的操作,都是行锁操作,MySQL为InnoDB引擎,id为自增主键

先创建一个测试表

CREATE TABLE `test` (

`id` int(0) NOT NULL AUTO_INCREMENT,

`name` varchar(20) NOT NULL,

`number` bigint(0) NOT NULL,

`age` int(0) NULL,

PRIMARY KEY (`id`)

) ENGINE = InnoDB;

看一下随便插入的几条数据

没有问题,使用共享锁看一下效果:

开启事务 begin;

给id为1的数据加共享锁 mysql> select * from test where id=1 lock in share mode;

分别使用加锁和不加锁查询id为1 的数据

都可以查询到数据

修改id为1 的数据看看

sql语句会一直停在这里,直到超时或者锁释放(事务提交或者回滚)

左边的事务提交后,右边的sql会执行,完成更新操作。

同样,删除操作也会等待锁释放才能操作,这里就不演示了。

再看一下另一种情况,左边锁住id为5的数据,右边更新id为1 的数据,不受影响。这就是行级锁,只会锁住相关的一行数据

排他锁的使用

还是使用test这张表

开启事务begin;

给id1的数据加排他锁select * from test where id = 1 for update;

在右边查询id为1的数据

查询语句会一直等待,直到超时或者锁释放(左边commit或者rollback)

左边commit后

使用排它锁对id为5的数据加锁后,更新id为5的数据

sql语句同样会等待,直到超时或者锁释放,删除操作也是一样

看一下对id为1的数据加锁,然后操作id不为1的数据的情况

没有问题,MySQL只是锁住了id为5的数据,其他的数据都可以操作。

看一下InnoDB引擎锁表的情况

我们常常说InnoDB是行锁,但是这里介绍一下它锁表的情况。因为name列没有索引,所以,在加行锁的时候,MySQL不能加正常加行锁,会锁住整张表。

InnoDB行锁是通过索引上的索引项来实现的,这一点MySQL与Oracle不同,后者是通过在数据中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味者:只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将使用表锁!

在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能。

再看另一种情况

使用排它锁对id为1的数据加锁时,使用不加锁的查询和没有约束的查询时,一样可以立刻查询到数据。只有使用加锁的查询或者更新和删除时才会等待锁释放。

总结

InnoDB的锁配合事务使用

MySQL有共享锁和排它锁

使用共享锁时,其他线程(连接)可以查询数据,但是不能更新和删除数据,使用排它锁时,不能查询数据不能更新数据,不能删除数据

MySQL的InnoDB引擎支持行级锁和表级锁,行级锁

InnoDB的行级锁是基于索引的,加锁是对索引加锁,加锁时没有索引时会锁住整张表

以上是我对MySQL锁的理解,文中如果有不正确的地方,还请各位大哥批评指正。

mysql 高并发写入锁表_使用mysql中的锁解决高并发问题相关推荐

  1. 锁失效_关于bigtable中chubby锁失效时的一点思考

    最近跟国内几家热门公司做分布式存储的大佬们聊了聊,过程十分愉快,但同时也有点小虐.说到底,自己在这个领域并没有很久的经验,很多东西仍停留在知其然而不知其所以然的地步.魔鬼藏在细节之处. 不过这也正好是 ...

  2. mysql批量insert数据锁表_批量插入数据产生锁阻塞的问题

    我的数据库表没有主键和外键,表上有索引字段, 5个入库线程批量入库操作,为什么会产生锁阻塞现象? 下面是我查到的session 512 阻塞了其他用户. --检查阻塞情况 select a.sid,a ...

  3. mysql bench建立一张表_使用MySQL Workbench建立数据库,建立新的表,向表中添加数据...

    点击上图中的"加号"图标,新建一个连接, 如上图,先输入数据库的账号密码,帐号默认为root,填好密码后 点击"OK",连接就建立好了,建立完成后,会出现一个长 ...

  4. MySQL怎么导出用户权限表_导出MySQL用户权限_MySQL

    在对MySQL数据库进行迁移的时候,有时候也需要迁移源数据库内的用户与权限.对于这个迁移我们可以从mysql.user表来获取用户的相关权限来生成相应的SQL语句,然后在目标服务器上来执行生成的SQL ...

  5. mysql创建带日期的表_在MySQL中创建带有日期的临时表

    要创建带有日期的临时表,请在MySQL中使用CREATE TEMPORARY TABLE.以下是语法- 语法create temporary table yourTableName( yourColu ...

  6. mysql读取和写入的峰值_计算MySQL的内存峰值公式

    -- 计算MySQL的内存峰值公式,计算所有的连接满了的情况下: select (@@key_buffer_size + @@query_cache_size + @@tmp_table_size + ...

  7. ORACLE数据库查询锁表语句sql脚本,以及删除锁信息脚本(数据库开发ETL、DBA必备)

    ORACLE数据库查询锁表语句sql脚本,以及删除锁信息脚本(数据库开发ETL.DBA必备) 文章目录 ORACLE数据库查询锁表语句sql脚本,以及删除锁信息脚本(数据库开发ETL.DBA必备) 前 ...

  8. 清空MySQL单库下所有表数据 || 删除MySQL单库下所有表

    一.清空MySQL单库下所有表数据 -- 清空MySQL单库下所有表数据 SELECT CONCAT('truncate table ',TABLE_NAME,';') AS PLEASE_EXEC_ ...

  9. mysql 数据库查看锁表_【数据库】MySQL查看是否锁表

    可直接在mysql命令行执行:show engine innodb status\G; 查看造成死锁的sql语句,分析索引情况,然后优化sql然后show processlist; 推荐课程:MySQ ...

最新文章

  1. java画出斜椭圆_【转】画图java源代码,只画直线,矩形,椭圆
  2. 42所双一流大学校长情况简介(2019年)
  3. [译] React 路由和 React 组件的爱恨情仇
  4. 爬虫-scrapy的中间件
  5. 网络推广网站总结降低网站跳出率的技巧有哪些?
  6. 从svn导入项目后处理一些报错信息
  7. 网速上不去,这锅真是路由器的?
  8. java jstack 死锁_利用jstack检测死锁DeadLock
  9. A - Junk-Mail Filter HDU - 2473
  10. OpenTSDB 开发指南之 Api操作数据
  11. 科研分享|一个论文关系网络可视化网站
  12. 使用PowerShell监视您的Azure计算机
  13. Pycharm Professional(专业版2018.2.1)最简单方法破解,亲测有效(转)
  14. 昨天,美团程序员的年终奖金可能没了!
  15. 自动设置为兼容模式html,什么是兼容模式?
  16. Dev中GridView——背景颜色改变
  17. POI处理Excel,条形图,散点图,折线图
  18. Pycharm中用Appium框架编写第一个自动化脚本
  19. 重装系统win11服务器未响应怎么修复操作
  20. css3 nth child 偶数,转载:CSS3 :nth-child(n)方法

热门文章

  1. (一)Activiti 数据库25张表——流程定义表9(ACT_RE_PROCDEF)
  2. Windows环境下设置php环境变量
  3. 嵌入式C语言构造类型与ASCII码表
  4. 以联名为文化致敬!HCK哈士奇×小王子 复古小冰箱即将上线!
  5. No target connected怎么解决
  6. Vue--vant-cell单元格组件跳转路由的三种方式
  7. Cocos2d-x 资源加密解密实践总结
  8. 关于ZFplayer升级3.0以后
  9. Popup导致背景变黑色
  10. 使用GPG加密邮件,进行数字签名和解密邮件