MySQL中的事务和锁机制

事务

1、Read Uncommitted

隔离级别最低的一种事务级别。在这种隔离级别下,一个事务会读到另一个事务更新后但未提交的数据,如果另一个事务回滚,那么当前事务读到的数据就是脏数据,这就是脏读(Dirty Read)。

在这个级别下,事务中的updateinsertdelete不管有没有提交,都会影响其他事务的select结果

2、Read Committed

Read Committed隔离级别下,一个事务可能会遇到不可重复读(Non Repeatable Read)的问题。
不可重复读是指,在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中,两次读取的数据就可能不一致。

在这个级别下,事务的updateinsertdelete只有在提交后,其他事务中select结果才会变

3、Repeatable Read

Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。
幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。

4、Serializable

Serializable是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。

虽然Serializable隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用Serializable隔离级别。

下边总结了一张图用来说明隔离级别之间的关系:
在这里插入图片描述

锁机制

按照锁的粒度划分:行锁、表锁、页锁
按照锁的使用方式划分:共享锁、排它锁(悲观锁的一种实现)
还有两种思想上的锁:悲观锁、乐观锁。
InnoDB中有几种行级锁类型:记录锁Record Lock、间隙锁Gap Lock、临键锁Next-key LockRecord Lock+Gap Lock

1、行锁

行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。有可能会出现死锁的情况。 行级锁按照使用方式分为共享锁和排他锁

共享锁用法(S锁、读锁):

select ... lock in share mode;

共享锁就是允许多个线程同时获取一个锁,一个锁可以同时被多个线程拥有。

排它锁用法(X 锁、写锁):

select ... for update

排它锁,也称作独占锁,一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释放之后才可能获取到锁。

2、表锁

表级锁是mysql锁中粒度最大的一种锁,表示当前的操作对整张表加锁,资源开销比行锁少,不会出现死锁的情况,但是发生锁冲突的概率很大。被大部分的mysql引擎支持,MyISAMInnoDB都支持表级锁,但是InnoDB默认的是行级锁。

共享锁用法:

LOCK TABLE table_name READ;

排它锁用法:

LOCK TABLE table_name WRITE;

解锁用法

unlock tables;

3、页锁

页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。BDB支持页级锁。

4、乐观锁和悲观锁

无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想。

4.1 悲观锁

在对任意记录进行修改前,先为该记录加上排他锁。

如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁。

4.2 乐观锁

相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。

一般的实现乐观锁的方式就是记录数据版本,为数据增加的一个版本标识。当读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对,如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据。

5、InnoDB锁的特性

  1. 在不通过索引条件查询的时候,InnoDB使用的是表锁!
  2. 由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。
  3. 当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。
  4. 即便在条件中使用了索引字段,但是否使用索引来检索数据是由MySQL通过判断不同 执行计划的代价来决定的,如果MySQL认为全表扫效率更高,比如对一些很小的表,它就不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,别忘了检查SQL的执行计划(explain查看),以确认是否真正使用了索引。

6、Record Lock锁、Gap Lock锁、Next-key Lock锁

  1. Record Lock锁(记录锁)

单条索引上加锁,record lock永远锁的是索引,而非数据本身,如果innodb表中没有索引,那么会自动创建一个隐藏的聚集索引,锁住的就是这个聚集索引。所以说当一条sql没有走任何索引时,那么将会在每一条聚集索引后面加X锁,这个表现上与表锁一致,但原理上和表锁是完全不同的。

  1. Gap Lock锁(间隙锁)

间隙锁,是在索引的间隙之间加上锁,这是为什么Repeatable Read隔离级别下能防止幻读的主要原因。

  1. Next-key Lock锁(临键锁)

临键锁,既锁住记录本身和索引之间的间隙,还锁住了索引之后的相邻的两个索引**(网上有说是锁住索引两边相邻的索引,但我测试后发现只锁住了之后两个相邻索引)**。

Gap Lock锁(间隙锁)和Next-key Lock锁(临键锁)只在范围查询时生效

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值