mysql数据库默认会不会加锁_Mysql/深入理解 mysql数据库锁

数据库锁的分类

  按照锁的粒度划分,可分为表级锁、行级锁、页级锁MyISAM支持表级锁,InnoDB支持表级锁和行级锁,

BDB支持页级锁(不常见),介于表级锁和行级锁之间。关于页,和数据库底层的存储结构有关,有机会讲一下。

  按照操作划分,可分为读锁(自动锁)、写锁(排它锁)

  按照加锁方式划分,可分为自动锁、显示锁

  按照操作划分,可分为DML锁、DDL锁

  按照使用方式划分,可分为乐观锁、悲观锁。其中乐观锁并发度较高,不会产生锁,其思想在编程语言种常用到,如JAVA底层的CAS。

  乐观锁:读锁又被称为共享锁,写锁又被称为排它锁。

  

  在进行增删改时,MySQL会默认加上写锁(排它锁);一个事务在 进行查询时,MySQL会默认加上读锁(共享锁),加上读锁时,其他事务

依然可以读取数据,但不能修改数据(不能加上写锁)。但是在InnDB中,MySQL对select做了优化,可以实现非阻塞读,并且通过MVCC+Gap Lock在

可重复读的隔离级别下避免幻读,详细分析请看下文。

  一个事务加上写锁时,其他事务既不能查询(不能加上读锁),也不能增删改(不能加上写锁),而是会堵塞住,等待其他事务释放锁。

MyISAM和InnoDB关于锁方面的区别是什么

  MyISAM默认用的是表级锁,不支持行级锁

  InnoDB默认用的行级锁,也支持表级锁

 

MySQL的事务默认是二段提交的,Mysql有一个系统变量autocommit变量,控制,默认为 on,

InnoDB;在不使用索引操作数据的时候,使用的表锁;在使用索引操作数据时 用的是 行级锁以及Gap锁(普通非唯一索引时用到)。

InnoDB还支持表级的意向锁,意向锁包括共享读锁(IS),排他写锁(IX)。但是行级锁未必一定比表级锁好,锁的粒度越小,代价越高,死锁概率越大。

表锁只需要扫描表头就可以,而行级锁需要扫描每一行,开销比较大。InnoDB必须有且仅有一个聚簇索引,数据是根据聚簇索引来存储的,数据和聚簇索引存放在同一个文件中,

通过聚簇索引查询数据效率很高,只需要查询一棵树。而非聚簇索引存放在另外的文件中,通过非聚簇索引查询需至少需要查询两棵树,第一次是根据非聚簇索引查询对应的主键,第二次是根据主键索引查询数据。

而MyISAM中,数据和索引是分离的,索引B+树的叶子节点保存的是指向数据的指针。因此MyISAM在增删改的系统中,也就是纯检索的系统中,性能要好于InnoDB。

 

MyISAM适合的场景

  1. 频繁执行全表count语句。MyISAM会在表头存储一个变量记录当前表中数据的行数,在执行count()时不时直接读取该变量即可,而对InnoDB表的执行count()时则需要遍历全表(可能是遍历某个索引,上一篇文章分析过了)。
  2. 对数据进行增删改的频率不高,查询非常频繁
  3. 没有事务

InnoDB适合的场景

  1. 数据增删改都相当频繁。InnoDB在进行增删改时,只会锁住对应的行,并发度较高。而MyISAM的表在进行增删改时会锁住整张表。
  2. 可靠性比较高,要求支持事务

 

数据库事务的四大特性(ACID)

  • 原子性(Atomic):事务要么全做,要不全都不做失败回滚
  • 一致性(Consistency):从一个一致状态转变到另一个一致状态,含义是完整性约束
  • 隔离性(Isolation):
  • 持久性(Durability):当系统或者介质发生故障时,数据库要确保已提交的更新不能丢失,对已提交事务的更新能恢复,主要体现在数据库的恢复性上。一旦一个事务被提交,DDMS要提供适当的冗余,使其耐得住故障。在InnoDB中,会将所有对数据库的修改操作保存在redo log中。

事务隔离级别,以及各级别下的并发访问问题

  更新丢失--主流数据库上在更新数据时都会加上写锁,因此MySQL所有事务隔离级别在数据库层面上均可避免该问题

  脏读--在READ-COMMITED级别下可以避免该问题

  不可重复读侧重于对同一条数据的修改,幻读侧重于新增和删除数据。事务隔离级别越高,安全性越高,串行度越高,并发度越低。

  Oracle默认的隔离级别是READ-COMMITED,MySQL默认的隔离级别是REPEATEABLE READ

InnoDB可重复读隔离级别下如何避免幻读

Next key锁 = 行锁+Gap锁。Gap锁是为了同一事务的两次当前读出现幻读的情况。Gap锁只在RR和Serializable下存在。

使用当前读删改查查询主键,如果where条件全部命中则不会用Gap锁,只会加记录锁。 

例如: select * from table where id in(1,3,5)

如果1,3,5全部命中,此时就算其他事务添加了数据,也不会影响该语句的第二次当前读,不会产生幻读现象,所以不会用Gap锁。另外使用

当前读删改查查询唯一键(非聚簇索引),除了给该索引所在的行加上行锁之外,也会在该行的聚簇索引上加锁,防止其他并发事务通过主键来更新数据。

 

-如果where条件部分命中或者全都不命中,且用到了主键或者唯一键,则会加Gap锁。

-Gap锁还会用在走非唯一索引或者不走索引的当前读中。 在非唯一性索引中,Gap锁的范围是左开右闭,其中表中主键的值也起到一定的作用,会锁住非唯一索引+对应的主键的值范围内的数据。

如果当前不走索引,则会锁住表中所有的Gap,相当于表锁,这种情况会降低并发,需要避免。

-为什么在不用索引的情况下,会所种所有的Gap?

  因为MySQL的数据是根据聚簇索引的叶子节点顺序存储的。在使用其他非聚簇唯一性索引时,是可以找到对应的聚簇索引的位置的,因此可以确定需要锁住的数据行的范围。

  但是使用非唯一性索引或者不使用索引时,是不能精确找到对应的聚簇索引的范围,因此会锁住所有的Gap,也就是整张表。

          

 

 

https://blog.csdn.net/weixin_33218578/article/details/113457966

posted @ 2024-01-26 15:42  wq9  阅读(258)  评论(0)    收藏  举报