测试:

4.5、innodb_locks_unsafe_for_binlog

innodb_locks_unsafe_for_binlog参数用来控制innodb中是否允许间隔锁,默认是OFF代表允许间隔锁,设置成ON则代表不使用间隔锁,只是使用行级锁

测试:

五、InnoDB事务隔离级别

5.1、简介

1)InnoDB存储引擎提供了四种事务隔离级别,分别是:READ UNCOMMITTED:读取未提交内容

READ COMMITTED:读取提交内容

REPEATABLE READ:可重复读,默认值。

SERIALIZABLE:串行化

2)可以通过--transaction-isolation参数设置实例级别的事务隔离级别,也可以通过set [session/global] transaction isolation level语句修改当前数据库链接或者是后续创建的所有数据库链接的事务隔离级别。每个事务隔离级别所对应的锁的使用方法都有所不同

5.2、REPEATABLE READ:可重复读

REPEATABLE READ:可重复读,默认值。

1)表明对同一个事务来说第一次读数据时会创建快照,在事务结束前的其他读操作(不加锁)会获得和第一次读相同的结果。

2)当读操作是加锁的读语句(select … for update或者lock in share mode),或者update和delete语句时,加锁的方式依赖于语句是否使用唯一索引访问唯一值或者范围值当访问的是唯一索引的唯一值时,则InnoDB会在索引行施加行锁

当访问唯一索引的范围值时,则会在扫描的索引行上增加间隔锁或者next-key锁以防止其他链接对此范围的插入

5.3、READ COMMITTED:读取提交内容

1)意味着每次读都会有自己最新的快照。对于加锁读语句(select … for update和lock in share mode),或者update,delete语句会在对应的行索引上增加锁,但不像可重复读一样会增加间隔锁,因此其他的事务执行插入操作时如果是插入非索引行上的数值,则不影响插入。

2)由于该隔离级别是禁用间隔锁的,所以会导致幻读的情况

3)如果是使用此隔离级别,就必须使用行级别的二进制日志

4)此隔离级别还有另外的特点:

对于update和delete语句只会在约束条件对应的行上增加锁。对update语句来说,如果对应的行上已经有锁,则InnoDB会执行半一致读的操作,来确定update语句对应的行在上次commit之后的数据是否在锁的范围,如果不是,则不影响update操作,如果是,则需要等待对应的锁解开

链接1

链接二

Mysql> set session transaction isolation level read committed;

mysql> set autocommit=0;

mysql> update temp set name='aaa' where id=1;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1 Changed: 1 Warnings: 0

mysql> set session transaction isolation level read committed;

mysql> set autocommit=0;

mysql> select * from temp;

+----+------+

| id | name |

+----+------+

| 1 | bb |

| 2 | bb |

| 3 | abc |

| 4 | abc |

mysql> commit;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from temp; ##同一个事务中能看到另一个事务已经提交的数据

+----+------+

| id | name |

+----+------+

| 1 | aaa |

| 2 | bb |

| 3 | abc |

| 4 | abc |

Commit;

5.4、READ UNCOMMITTED:读取未提交内容

READ UNCOMMITTED:读取未提交内容,所读到的数据可能是脏数据链接

链接2

mysql>set session transaction isolation level read uncommitted;

Query OK, 0 rows affected (0.00 sec)

mysql> set autocommit=0;

Query OK, 0 rows affected (0.00 sec)

mysql> update temp set name='bb';

Query OK, 3 rows affected (0.00 sec)

Rows matched: 4 Changed: 3 Warnings: 0

mysql> set session transaction isolation level read uncommitted;

Query OK, 0 rows affected (0.00 sec)

mysql> set autocommit=0;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from temp; ##已经可以看到未提交的数据

+----+------+

| id | name |

+----+------+

| 1 | bb |

| 2 | bb |

| 3 | bb |

| 4 | bb |

+----+------+

4 rows in set (0.00 sec)

mysql> commit;

Query OK, 0 rows affected (0.00 sec)

Commit;

5.5、SERIALIZABLE:串行化

此隔离级别更接近于可重复读这个级别,只是当autocommit功能被禁用后,InnoDB引擎会将每个select语句隐含的转化为select … lock in share mode链接1

链接2

mysql> set session transaction isolation level SERIALIZABLE;

Query OK, 0 rows affected (0.00 sec)

mysql> set autocommit=0;

Query OK, 0 rows affected (0.00 sec)

mysql> update temp set name='bb';

Query OK, 0 rows affected (0.00 sec)

Rows matched: 4 Changed: 0 Warnings: 0

mysql> set session transaction isolation level SERIALIZABLE;

Query OK, 0 rows affected (0.00 sec)

mysql> set autocommit=0;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from temp; ##锁等待

mysql> commit;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from temp;

+----+------+

| id | name |

+----+------+

| 1 | aa |

| 2 | aa |

| 3 | aa |

| 4 | aa |

+----+------+

Commit;

六、Autocommit/commit/rollback

1)当设置autocommit属性开启时,每个SQL语句都会隐含成为独立的事务。

2)默认情况下autocommit属性是开启的,也就意味着当每个SQL语句最后执行结果不返回错误时都会执行commit语句,当返回失败时会执行rollback语句

3)而当autocommit属性开启时,可以通过执行start transaction或者begin语句来显示的开启一个事务,而事务里可以包含多个SQL语句,最终事务的结束是由commit或者rollback来终结

4)而当在数据库链接里执行set autocommit=0代表当前数据库链接禁止自动提交,事务的终结由commit或者rollback决定,同时也意味着下一个事务的开始

5)如果一个事务在autocommit=0的情况下数据库链接退出而没有执行commit语句,则这个事务会回滚

6)一些特定的语句会隐含的终结事务,就好比是执行了commit语句

7)commit语句代表将此事务的数据修改永久化,并对其他事务可见,而rollback则代表将此事务的数据修改回滚。

8)commit和rollback都会把当前事务执行所施加的锁释放

9)当使用多语句事务时,如果全局的autocommit属性是开启的,则开始此事务的方式可以使set autocommit=0将当前链接的属性关闭,最后执行commit和rollback;或者是显示的使用start transaction语句开启事务

七、一致读

1)在默认的隔离级别下一致读是指InnoDB在多版本控制中在事务的首次读时产生一个镜像,在首次读时间点之前其他事务提交的修改可以读取到,而首次读时间点之后其他事务提交的修改或者是未提交的修改都读取不到

2)唯一例外的情况是在首次读时间点之前的本事务未提交的修改数据可以读取到

3)在读取提交数据隔离级别下,一致读的每个读取操作都会有自己的镜像

4)一致读操作不会施加任何的锁,所以就不会阻止其他事务的修改动作

5)一致读在某些DDL语句下不生效:碰到drop table语句时,由于InnoDB不能使用被drop的表,所以无法实现一致读

碰到alter table语句时,也无法实现一致读

6)当碰到insert into… select, update … select和create table … select语句时,在默认的事务隔离级别下,语句的执行更类似于在读取提交数据的隔离级别下

八、加锁读

8.1、加锁读介绍

1)当在一个事务中在读操作结束后会执行insert和update操作时,普通的读操作无法阻止其他事务对相同数据执行修改操作,所以InnoDB提供了两种在读操作时就增加锁的方式

2)select … lock in share mode:在读取的行数据上施加共享锁,其他的事务可以读相同的数据但无法修改;如果在执行此语句时有其他事务对相同的数据已经施加了锁,则需要等待事务完结释放锁

3)select … for update:和update操作一样,在涉及的行上施加排他锁,并阻止任何其他事务对涉及行上的修改操作、以及加锁读操作,但不会阻止对涉及行上的一般读(不加锁)操作

4)同样,锁的释放也是在事务提交或者回滚之后

8.2、加锁读应用

1)比如在子表中插入一行数据,要确保对应的列在父表中有值,通过一般的读操作先查父表有值然后再插入的方法是不保险的,因为在读操作和插入操作之间就有可能其他事务会将父表的数据修改掉。那保险的做法是在查询父表是用加锁读的方式

创建测试表:

mysql> create table temp(id int primary key,name varchar(10));

mysql> create table temp_child(id int primary key,temp_id int,constraint f_1 foreign key (temp_id) references temp(id));

mysql> insert into temp values(1,'a'),(2,'b'),(3,'c'),(4,'d');

链接1

链接2

mysql> set autocommit=0;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from temp;

+----+------+

| id | name |

+----+------+

|  1 | a    |

|  2 | b    |

|  3 | c    |

|  4 | d    |

+----+------+

mysql> set autocommit=0;

Query OK, 0 rows affected (0.00 sec)

mysql> delete from temp where id=3;

Query OK, 1 row affected (0.00 sec)

mysql> commit;

Query OK, 0 rows affected (0.00 sec)

mysql> select * from temp;

+----+------+

| id | name |

+----+------+

|  1 | a    |

|  2 | b    |

|  3 | c    |

|  4 | d    |

+----+------+

mysql> insert into temp_child values(1,3);  #报外键冲突

ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`locktest`.`temp_child`, CONSTRAINT `f_1` FOREIGN KEY (`temp_id`) REFERENCES `temp` (`id`))

mysql> rollback;

2)比如当表中有一个行数计数字段时,使用一致读和lock in share mode都有可能导致重复错误数据出现,因为有可能两个事务会读到相同的值,在这种情况下就要使用select … for update语句保证一个事务在读时,另一个事务必须等待

九、SQL语句对应的锁

1)加锁读,修改和删除SQL语句都会在索引扫描过的每一行增加锁,也就是说不光是在where条件限制的索引行上增加锁,也会对扫描到的间隔增加间隔锁

2)如果SQL语句是使用二级索引查找数据而且施加的是排他锁,则InnoDB也会在对应的聚簇索引行上施加锁

3)如果SQL语句没有任何索引可以使用,则MySQL需要扫描全表数据,而每行数据都会被施加锁,所以一个良好的习惯是为InnoDB添加合适的索引

4)针对不同的语句,InnoDB会施加不同的锁:

5)Select…from语句属于一致性读,在默认情况下不施加任何的锁,除非在可串行化隔离级别下,会施加共享next-key锁在扫描的索引行上,当碰到使用唯一索引查找唯一值时只在唯一值上施加锁

6)Select…lock in share mode语句会在索引扫描行上施加共享next-key锁,除非是当碰到使用唯一索引查找唯一值时只在唯一值上施加锁

7)Select…for update语句会对扫描索引的行上施加排他next-key锁,除非是当碰到使用唯一索引查找唯一值时只在唯一值上施加锁

8)Update语句会对扫描索引的行上施加排他next-key锁,除非是当碰到使用唯一索引查找唯一值时只在唯一值上施加锁。

9)Delete语句会对扫描索引的行上施加排他next-key锁,除非是当碰到使用唯一索引查找唯一值时只在唯一值上施加锁

10)Insert语句会对索引扫描的行上施加锁,但不是next-key锁,所以不会阻止其他事务对该行值前的间隔上插入数据

11)Insert into T select…from S语句会对插入到T表的行施加排他锁(非间隔锁),而在默认隔离级别下会对访问的S表上的行施加共享next-key锁

12)当表上有外键约束时,对任何的insert,update和delete操作都会在需要检查外键约束的行上施加共享行锁

13)Lock table语句是施加表级锁

十、幻读

1)幻读问题发生在同一个事务中当相同的读操作在前后两次读数据时返回不同的结果集。

2)比如在表的ID字段上有一个索引,当希望对ID>100的数据进行后续修改时,我们会使用如下的语句: SELECT * FROM child WHERE id > 100 FOR UPDATE,而如果表里目前只有90和102两个值时,如果没有间隔锁锁住90到102之间的间隔,则其他的事务会插入比如101这个值,这样的话在第二次读数据时就会返回三行记录而导致幻读

3)为了阻止幻读情况的发生,InnoDB使用了一种方法next-key锁将索引行锁和间隔锁合并在一起。InnoDb会在索引扫描的行上施加行级共享锁或者排他锁,而next-key锁也会在每个索引行之前的间隔上施加锁,会导致其他的session不能在每个索引之前的间隔内插入新的索引值

4)间隔锁会施加在索引读碰到的行数据上,所以对上例来说为了阻止插入任何>100的值,也会将最后扫描的索引值102之前的间隔锁住

十一、InnoDB锁性能监控

十二、InnoDB死锁

12.1、死锁介绍

1)死锁的情况发生在不同的的事务相互之间拥有对方需要的锁,而导致相互一直无限等待

2)死锁可能发生在不同的事务都会对多个相同的表和相同的行上施加锁,但事务对表的操作顺序不相同

3)为了减少死锁的发生,要避免使用lock table语句,要尽量让修改数据的范围尽可能的小和快速;当不同的事务要修改多个表或者大量数据时,尽可能的保证修改的顺序在事务之间要一致

4)默认情况下InnoDB下的死锁自动侦测功能是开启的,当InnoDB发现死锁时,会将其中的一个事务作为牺牲品回滚。

5)通过innodb_lock_wait_timeout参数配置自动侦测功能是否开启,如果关闭的话,InnoDB就会使用innodb_lock_wait_timeout参数来自动回滚等待足够时间的事务

6)可以通过show engine innodb status语句查看最后一次发生死锁的情况

7)默认情况下死锁检测功能是开启的,当死锁发生时InnoDB会自动检测到并牺牲(回滚)其中的一个或者几个事务,以便让其他的事务继续执行下去。InnoDB选择牺牲的事务往往是代价比较小的事务,其代价计算是根据事务insert,update, delete的数据行规模决定

8)如果事务中的某个语句因为错误而回滚,则这个语句上的锁可能还会保留,是因为InnoDB仅会存储行锁信息,而不会存储行锁是由事务中的哪个语句产生的

9)如果在一个事务中,select语句调用了函数,而函数中的某个语句执行失败,则那个语句会回滚,如果在整个事务结束时执行rollback,则整个事务回滚

10)可以通过innodb_deadlock_detect 参数关闭死锁检测功能,而仅仅用innodb_lock_wait_timeout的功能来释放锁等待

12.2、减少死锁发生的方法

在事务性数据库中,死锁是个经典的问题,但只要发生的频率不高则死锁问题不需要太过担心

查看死锁的方法有两种:通过show engine innodb status命令可以查看最后一个死锁的情况

通过innodb_print_all_deadlocks参数配置可以将所有死锁的信息都打印到MySQL的错误日志中

减少死锁发生的方法:尽可能的保持事务小型化,减少事务执行的时间可以减少发生影响的概率

及时执行commit或者rollback,来尽快的释放锁

可以选用较低的隔离级别,比如如果要使用select... for update和select...lock in share mode语句时可以使用读取提交数据隔离级别

当要访问多个表数据或者要访问相同表的不同行集合时,尽可能的保证每次访问的顺序是相同的。比如可以将多个语句封装在存储过程中,通过调用同一个存储过程的方法可以减少死锁的发生

增加合适的索引以便语句执行所扫描的数据范围足够小

尽可能的少使用锁,比如如果可以承担幻读的情况,则直接使用select语句,而不要使用select...for update语句

如果没有其他更好的选择,则可以通过施加表级锁将事务执行串行化,最大限度的限制死锁发生

12.3、死锁监控

十三、补充:锁的监控及处理

13.1、模拟锁等待定位过程

13.2、优化项目:锁的监控及处理

mysql 事务涉及锁吗_MySQL-锁机制和事务相关推荐

  1. mysql锁优化_mysql锁以及配置优化

    1. 看有没有锁等待 SHOW STATUS LIKE 'innodb_row_lock%'; 2. 查看哪个事务在等待(被阻塞了) USE information_schema SELECT * F ...

  2. mysql insert是锁表还是锁行_mysql 锁表还是锁行

    关于mysql的锁行还是锁表,这个问题,今天算是有了一点头绪,mysql 中 innodb是锁行的,但是项目中居然出现了死锁,锁表的情况.为什么呢?先看一下这篇文章. 做项目时由于业务逻辑的需要,必须 ...

  3. firebird 行级锁问题_MySQL 锁

    数据库系统使用锁是为了支持对共享资源进行并发访问,保障数据的完整性和一致性. 锁设计 不同存储引擎的锁设计是不一样的,InnoDB 存储引擎会在行级对数据上锁,不过 InnoDB 存储引擎也会在数据库 ...

  4. mysql事物及事物等级_MySQL事物原理及事务隔离级别

    mysql事物 事务是访问数据库的一个操作序列,数据库应用系统通过事务集来完成对数据库的存取.事务的正确执行使得数据库从一种状态转换为另一种状态. 事务必须服从ISO/IEC所制定的ACID原则.AC ...

  5. mysql不支持python3吗_MySQL的4种事务隔离级别你还不清楚吗?

    前言 现在想把数据库这块整理出来,尽量用最简洁的语言描述出来,供新人参考. 首先创建一个表 account.创建表的过程略过(由于 InnoDB 存储引擎支持事务,所以将表的存储引擎设置为 InnoD ...

  6. mysql 锁设置_MySQL锁之二:锁相关的配置参数

    锁相关的配置参数: mysql> SHOW VARIABLES LIKE '%timeout%';+-----------------------------+----------+ | Var ...

  7. mysql 并发锁表_MySQL锁表的用法,防止并发情况下的重复数据

    早就听说lock tables和unlock tables这两个命令,从字面也大体知道,前者的作用是锁定表,后者的作用是解除锁定.但是具体如何用,怎么用,不太清楚.今天详细研究了下,总算搞明白了2者的 ...

  8. mysql锁表_MYSQL锁表问题的解决方法

    本文实例讲述了MYSQL锁表问题的解决方法.分享给大家供大家参考,具体如下: 很多时候!一不小心就锁表!这里讲解决锁表终极方法! 案例一 mysql>show processlist; 参看sq ...

  9. mysql新增字段会锁表_MySQL锁(二)表锁:为什么给小表加字段会导致整个库挂掉?...

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

  10. mysql 锁监视器_MySQL锁监视器

    还在为看不懂何登成的加锁处理分析文章感到羞愧吗? 还在因为何大师的笔误,陷入深深的迷茫吗? 只要你拥有大于5.6.16版本的MySQL,锁监视器你值得拥有! 快速入门 开启 set GLOBAL in ...

最新文章

  1. adb 连接不上电脑怎么办?
  2. Effective C++ 小笔记:条款13-17(第三章)
  3. “面试不败计划”:面试题基础一
  4. BOOST_SCOPE_EXIT宏相关的测试程序
  5. python3 hash算法使用
  6. SharePoint Welcome.ascx 控件自定义样式的另类解决方式
  7. shell中四大循环介绍及使用
  8. OPPO Enco Free真无线耳机:超低延迟高音质 智慧触控看得见
  9. axios流输出excel
  10. 四种依恋类型_【工具】成人依恋量类型介绍
  11. html5液体效果,HTML5/CSS3/SVG实现的液体掉落(滑落)动画
  12. 关于C#中枚举与字符串与数字之间的转换
  13. Asp.net mvc+三层架构(注册篇)
  14. xp计算机保护系统,XP系统总是弹出“Windows文件保护”窗口提示的解决方法
  15. 双向循环链表讲解及实现
  16. 14个UI精美功能强大的Android应用设计模板
  17. Python 数据分析微专业课程--项目实战09 房价影响因素挖掘
  18. Veil-Evasion免杀
  19. win10系统更新后打开chrome浏览器几秒后自动闪退
  20. 带薪拉屎是一种怎样的体验

热门文章

  1. 皮一皮:钢铁直女?鉴定了,钢的不能再钢!
  2. 2021年6月程序员工资排行榜,南京这是怎么了?有啥大动作吗?
  3. 拼多多面试真题:如何用 Redis 统计独立用户访问量!
  4. 换个姿势学设计模式:策略模式
  5. Sentinel Dashboard 中修改规则同步到 Nacos
  6. Spring Boot 2.0正式发布,升还是不升呢?
  7. 三刺激值计算公式_常用的车削、铣削、钻削加工计算公式全在这里了,随用随查...
  8. 清华开源ResRep:剪枝SOTA!用结构重参数化实现CNN无损压缩 | ICCV 2021
  9. python查看环境路径
  10. python 比较两个字符串