MySql-锁与事物

    • 锁的简介
        • 为什么需要锁?
      • 锁的概念
      • MySQL 中的锁
      • 表锁与行锁的使用场景
    • MyISAM 锁
      • 共享读锁
      • 独占写锁
        • 总结:
    • InnoDB 锁
      • 语法
      • 注意:
    • 锁的等待问题
  • 事务
    • 什么存储引擎支持事务
    • 事务特性
      • 原子性(atomicity)
      • 一致性(consistency)
      • 持久性(durability)
      • 隔离性(isolation)
        • 事务并发问题
        • 未提交读(READ UNCOMMITED)脏读
        • 已提交读 (READ COMMITED)不可重复读
        • 可重复读(REPEATABLE READ)
        • 可串行化(SERIALIZABLE)

锁的简介

为什么需要锁?

到淘宝上买一件商品,商品只有一件库存,这个时候如果还有另一个人买,那么如何解决是 你买到还是另一个人买到的问题?

锁的概念

  • 锁是计算机协调多个进程或线程并发访问某一资源的机制。
  • 在数据库中,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、 有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个 重要因素。
  • 锁对数据库而言显得尤其重要,也更加复杂。

MySQL 中的锁

  • 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发 度最低。
  • 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发 度也最高。
  • 页面锁(gap 锁,间隙锁):开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度 界于表锁和行锁之间,并发度一般。

表锁与行锁的使用场景

表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如 OLAP 系统
行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有并发查询的应用,如 一些在线事务处理(OLTP)系统。
很难笼统地说哪种锁更好,只能就具体应用的特点来说哪种锁更合适

MyISAM 锁

MySQL 的表级锁有两种模式:
表共享读锁(Table Read Lock)
表独占写锁(Table Write Lock)

共享读锁

语法:lock table 表名 read

  1. lock table testmysam READ 启动另外一个 session select * from testmysam 可以查询
  2. insert into testmysam value(2); update testmysam set id=2 where id=1; 报错
    3.在另外一个 session 中
    insert into testmysam value(2); 等待
    4.在同一个 session 中
    insert into account value(4,'aa',123); 报错
    select * from account ; 报错
    5.在另外一个 session 中
    insert into account value(4,'aa',123); 成功
    6.加锁在同一个 session 中 select s.* from testmysam s 报错
    lock table 表名 as 别名 read;

独占写锁

1.lock table testmysam WRITE
在同一个 session 中

insert testmysam value(3);
delete from testmysam where id = 3
select * from testmysam

2.对不同的表操作(报错)

select s.* from testmysam s
insert into account value(4,'aa',123);

3.在其他 session 中 (等待)

select * from testmysam

总结:

  • 读锁,对 MyISAM 表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一 表的写请求
  • 读锁,对 MyISAM 表的读操作,不会阻塞当前 session 对表读,当对表进行修改会报错
  • 读锁,一个 session 使用 LOCK TABLE 命令给表 f 加了读锁,这个 session 可以查询锁定表 中的记录,但更新或访问其他表都会提示错误;
  • 写锁,对 MyISAM 表的写操作,则会阻塞其他用户对同一表的读和写操作;
  • 写锁,对 MyISAM 表的写操作,当前 session 可以对本表做 CRUD,但对其他表进行操作 会报错

InnoDB 锁

在 mysql 的 InnoDB 引擎支持行锁

  • 共享锁又称:读锁。当一个事务对某几行上读锁时,允许其他事务对这几行进行读操作,但 不允许其进行写操作,也不允许其他事务给这几行上排它锁,但允许上读锁。
  • 排它锁又称:写锁。当一个事务对某几个上写锁时,不允许其他事务写,但允许读。更不允 许其他事务给这几行上任何锁。包括写锁。

语法

上共享锁的写法:lock in share mode
例如: select * from 表 where 条件 lock in share mode;
上排它锁的写法:for update
例如:select * from 表 where 条件 for update;

注意:

1.两个事务不能锁同一个索引。
2.insert ,delete , update 在事务中都会自动默认加上排它锁。
3.行锁必须有索引才能实现,否则会自动锁全表,那么就不是行锁了。

  CREATE TABLE testdemo ( `id` int(255) NOT NULL , `c1` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `c2` int(50) NULL DEFAULT NULL , PRIMARY KEY (`id`), INDEX `idx_c2` (`c2`) USING BTREE )ENGINE=InnoDB; insert into testdemo VALUES(1,'1',1),(2,'2',2);
  1. BEGIN select * from testdemo where id =1 for update
    在另外一个 session 中 update testdemo set c1 = '1' where id = 2 成功
    update testdemo set c1 = '1' where id = 1 等待
  2. BEGIN update testdemo set c1 = '1' where id = 1
    在另外一个 session 中 update testdemo set c1 = '1' where id = 1 等待
  3. BEGIN update testdemo set c1 = '1' where c1 = '1'
    在另外一个 session 中 update testdemo set c1 = '2' where c1 = '2' 等待
  4. 第一个 session 中 select * from testdemo where id =1 for update
    第二个 session select * from testdemo where id =1 lock in share mode
    回到第一个 session UNLOCK TABLES 并不会解锁
    使用 commit 或者 begin 或者 ROLLBACK 才会解锁
  5. 再来看下表锁
    lock table testdemo WRITE
    使用 commit,ROLLBACK 并不会解锁
    使用 UNLOCK TABLES 或者 begin 会解锁

锁的等待问题

好了,掌握了上面这些,你对锁的了解已经超过了很多同学,那么现在来说一个实际的问 题,在工作中经常一个数据被锁住,导致另外的操作完全进行不下去。

你肯定碰到过这问题,有些程序员在 debug 程序的时候,经常会锁住一部分数据库的数据, 而这个时候你也要调试这部分功能,却发现代码总是运行超时,你是否碰到过这问题了,其 实这问题的根源我相信你也知道了。
举例来说,有两个会话。
程序员甲,正直调试代码
BEGIN
SELECT * FROM testdemo WHERE id = 1 FOR UPDATE
你正直完成的功能也要经过那部分的代码,你得上个读锁
BEGIN
SELECT * FROM testdemo WHERE id = 1 lock in share mode

这个时候很不幸,你并不知道发生了什么问题,在你调试得过程中永远就是一个超时得异常, 而这种问题不管在开发中还是在实际项目运行中都可能会碰到,那么怎么排查这个问题呢? 这其实也是有小技巧的。

select * from information_schema.INNODB_LOCKS;


真好,我通过这个 sql 语句起码发现在同一张表里面得同一个数据有了 2 个锁其中一个是 X (写锁),另外一个是 S(读锁),我可以跳过这一条数据,使用其他数据做调试
可能如果我就是绕不过,一定就是要用这条数据呢?吼一嗓子吧(哪个缺德的在 debug 这个 表,请不要锁这不动),好吧,这是个玩笑,其实还有更好的方式来看

select * from sys.innodb_lock_waits


我现在执行的这个 sql 语句有了,另外看下最下面,kill 命令,你在工作中完全可以通过 kill 吧阻塞了的 sql 语句给干掉,你就可以继续运行了,不过这命令也要注意使用过,如果某同 事正在做比较重要的调试,你 kill,被他发现可能会被暴打一顿。

上面的解决方案不错,但如果你的 MySQL 不是 5.7 的版本呢?是 5.6 呢,你根本就没有 sys 库,这个时候就难办了,不过也是有办法的。

SELECT r.trx_id waiting_trx_id,
r.trx_mysql_thread_id waiting_thread,
r.trx_query waiting_query,
b.trx_id blocking_trx_id,
b.trx_mysql_thread_id blocking_thread
FROM
information_schema.innodb_lock_waits w
INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;


看到没有,接下来你是否也可以执行 kill 29 这样的大招了。

事务

现在的很多软件都是多用户,多程序,多线程的,对同一个表可能同时有很多人在用,为保 持数据的一致性,所以提出了事务的概念。

A 给 B 要划钱,A 的账户-1000 元, B 的账户就要+1000 元,这两个 update 语句必须作为 一个整体来执行,不然 A 扣钱了,B 没有加钱这种情况很难处理。

什么存储引擎支持事务

  1. 查看数据库下面是否支持事务(InnoDB 支持)?
show engines;
  1. 查看 mysql 当前默认的存储引擎?
 show variables like '%storage_engine%';
  1. 查看某张表的存储引擎?
  show create table 表名 ;
  1. 对于表的存储结构的修改?
    建立 InnoDB 表:Create table … type=InnoDB; Alter table table_name type=InnoDB;

事务特性

事务应该具有 4 个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为 ACID 特 性。

  • 原子性(atomicity)
  • 一致性(consistency)
  • 隔离性(isolation)
  • 持久性(durability)

原子性(atomicity)

一个事务必须被视为一个不可分割的最小单元,整个事务中的所有操作要么全部提交成功, 要么全部失败,对于一个事务来说,不可能只执行其中的一部分操作
小明给 小红 打钱
1.小明银行卡扣除 500 元
2小红银行卡增加 500
整个事务要么全部成功,要么全部失败

一致性(consistency)

一致性是指事务将数据库从一种一致性转换到另外一种一致性状态,在事务开始之前和事务 结束之后数据库中数据的完整性没有被破坏
小红给小明打钱
1、小红银行卡扣除500
2、小明银行卡增加500
2、小明银行卡增加1000
扣除的钱(-500) 与增加的钱(500) 相加应该为 0

持久性(durability)

一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,已经提交的 修改数据也不会丢失
并不是数据库的角度完全能解决

隔离性(isolation)

一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事 务是隔离的,并发执行的各个事务之间不能互相干扰。 (对数据库的并行执行,应该像串行执行一样)

  • 未提交读(READ UNCOMMITED)脏读
  • 已提交读 (READ COMMITED)不可重复读
  • 可重复读(REPEATABLE READ)
  • 可串行化(SERIALIZABLE)
    mysql 默认的事务隔离级别为 repeatable-read
show variables like '%tx_isolation%';

事务并发问题

  • 脏读:事务 A 读取了事务 B 更新的数据,然后 B 回滚操作,那么 A 读取到的数据是脏 数据
  • 不可重复读:事务 A 多次读取同一数据,事务 B 在事务 A 多次读取的过程中,对数 据作了更新并提交,导致事务 A 多次读取同一数据时,结果 不一致。
  • 幻读:系统管理员 A 将数据库中所有学生的成绩从具体分数改为 ABCDE 等级,但是系 统管理员 B 就在这个时候插入了一条具体分数的记录,当系统管理员 A 改结束后发现 还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不 可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

未提交读(READ UNCOMMITED)脏读

show variables like '%tx_isolation%';
set SESSION TRANSACTION ISOLATION LEVEL read UNCOMMITTED;

一个 session 中

start TRANSACTION
update account set balance = balance -50 where id = 1

另外一个 session 中查询

select * from account

回到第一个 session 中 回滚事务

ROLLBACK
在第二个 session 中

select * from account

在另外一个 session 中读取到了为提交的数据,这部分的数据为脏数据

已提交读 (READ COMMITED)不可重复读

show variables like '%tx_isolation%';set SESSION TRANSACTION ISOLATION LEVEL read committed;

一个 session 中

start TRANSACTION
update account set balance = balance -50 where id = 1

另外一个 session 中查询 (数据并没改变)

select * from account

回到第一个 session 中 回滚事务
commit
在第二个 session 中
select * from account (数据已经改变)

可重复读(REPEATABLE READ)

show variables like '%tx_isolation%';set SESSION TRANSACTION ISOLATION LEVEL repeatable read;

一个 session 中

start TRANSACTION
update account set balance = balance -50 where id = 1

另外一个 session 中查询 (数据并没改变)

select * from account

回到第一个 session 中 回滚事务

commit

在第二个 session 中
select * from account (数据并未改变)

可串行化(SERIALIZABLE)

show variables like '%tx_isolation%';
set SESSION TRANSACTION ISOLATION LEVEL serializable;

1.开启一个事务

begin select * from account #发现 3 条记录

2.开启另外一个事务

begin select * from account #发现 3 条记录 也是 3 条记录
insert into account VALUES(4,'deer',500) #发现根本就不让插入
  1. 回到第一个事务 commit

七、MySql-锁与事物相关推荐

  1. 事物的级别_面试官问:MySQL锁与事物隔离级别你知道吗?

    本文作者:何建辉(公众号:org_yijiaoqian) 点赞再看,养成习惯,微信搜一搜[一角钱小助手]关注更多原创技术文章. 本文 GitHub org_hejianhui/JavaStudy 已收 ...

  2. 面试官问:MySQL锁与事物隔离级别你知道吗?

    点赞再看,养成习惯,微信搜一搜[一角钱小助手]关注更多原创技术文章. 本文 GitHub org_hejianhui/JavaStudy 已收录,有我的系列文章. 前言 MySQL索引底层数据结构与算 ...

  3. MySQL锁的灵魂七拷问

    墨墨导读:本文罗列出有关MySQL锁的七个问题,这些,你遇到过吗? 一.缘起 假设你想给别人说明,MySQL 里面是有锁的,你会怎么做? 大多数人,都会开两个窗口,分别起两个事务,然后 update ...

  4. mysql 聊聊InnoDB七种锁

    前言 本文将跟大家聊聊InnoDB的锁.本文比较长,包括一条SQL是如何加锁的,一些加锁规则.如何分析和解决死锁问题等内容,建议耐心读完,肯定对大家有帮助的. 为什么需要加锁呢? InnoDB的七种锁 ...

  5. mysql三锁,mysql锁机制之表锁(三)

    顾名思义,表锁就是一锁锁一整张表,在表被锁定期间,其他事务不能对该表进行操作,必须等当前表的锁被释放后才能进行操作.表锁响应的是非索引字段,即全表扫描,全表扫描时锁定整张表,sql语句可以通过执行计划 ...

  6. mysql锁相关讲解及其应用——《深究mysql锁》

    一.mysql的锁类型 (1) 共享/排它锁(Shared and Exclusive Locks) 共享锁和排他锁是InnoDB引擎实现的标准行级别锁. 拿共享锁是为了让当前事务去读一行数据. 拿排 ...

  7. 五分钟了解Mysql的行级锁——《深究Mysql锁》

    延伸阅读: 三分钟了解Mysql的表级锁 一分钟深入Mysql的意向锁 mysql锁相关讲解及其应用--<深究mysql锁>了解锁前,一定要先看这篇,了解什么是MVCC,如果我们学习锁,没 ...

  8. 三分钟了解Mysql的表级锁——《深究Mysql锁》

    延伸阅读: 五分钟了解Mysql的行级锁 一分钟深入Mysql的意向锁 mysql锁相关讲解及其应用--<深究mysql锁>了解锁前,一定要先看这篇,了解什么是MVCC,如果我们学习锁,没 ...

  9. 深入理解 MySQL ——锁、事务与并发控制

    本文对 MySQL 数据库中有关锁.事务及并发控制的知识及其原理做了系统化的介绍和总结,希望帮助读者能更加深刻地理解 MySQL 中的锁和事务,从而在业务系统开发过程中可以更好地优化与数据库的交互. ...

  10. 第四十九期:大牛总结的MySQL锁优化,写得太好了!

    随着 IT 技术的飞速发展,各种技术层出不穷,让人眼花缭乱.尽管技术在不断更新换代,但是有些技术依旧被一代代 IT 人使用至今. 作者:崔皓 随着 IT 技术的飞速发展,各种技术层出不穷,让人眼花缭乱 ...

最新文章

  1. 这次不忽悠:3个成功案例告诉你,开一家AI公司其实不难
  2. [IE技巧] IE Security Zone 的注册表设置
  3. Spring Boot 2.x基础教程:默认数据源Hikari的配置详解
  4. 休眠:保存vs持久并保存或更新
  5. 第 6-1 课:Spring 核心 + 面试题
  6. 转 Phpstorm调试详解(包含命令行以及浏览器)
  7. linux 启动nacos报错_Spring Cloud:Alibaba 之 Nacos
  8. HTML和CSS实现品优购首页
  9. 安装matlab7.0步骤,Matlab 7.0 安装指导
  10. 乌班图系统设置系统语言,以及中文输入法
  11. java beanshell_使用beanshell实现JAVA代码动态运行
  12. 小米电视4s android,小米电视系列ROOT教程(含4A,4S,4X等Android6.0.1版机型)
  13. JavaScript系列-闭包
  14. 在springboot中使用腾讯QQ邮箱发送邮件时出现的错误
  15. Android 比Zing 更快的二维码 条形码扫描Zbar
  16. 腾讯免费企业邮箱服务器,如何免费申请腾讯企业邮箱?
  17. js用map筛选指定元素(ES6的map方法)
  18. oracle数据库拼接sql语句字符串问题
  19. 结对项目:自动生成小学四则运算题目程序
  20. IM消息重试机制Java实现_IM群聊消息的已读回执功能该怎么实现?

热门文章

  1. JavaScript:变量提升作用域
  2. *与**在python中的使用
  3. 微服务架构下的轻量级定时任务解决方案
  4. 怎么购买企业邮箱,才不被坑?
  5. Ubuntu 16.04服务器 配置
  6. Web 学习之跨域问题及解决方案
  7. 时序分析基本概念介绍——STA概述
  8. linux运行查依赖,linux运行命令缺少依赖库的查找方法
  9. ConcurrentHashMap内部原理浅析
  10. 天津科技大学计算机科学与技术专业怎么样,2021年天津科技大学重点专业排名有哪些,招生优势专业排行榜...