MySQL基础知识--事务 · 锁

MySQL基础知识–事务 · 锁

事务

什么是事务?事务的作用是什么?

​ 事务本质上是数据库操作的一种安全机制。
作用:
A.能保证一组对数据库操作要么同时成功,要么同时失败;
B.多个同时对数据库的操作不受相互影响。


事务的四大特性是什么?

——ACID(只有InnoDB才支持事务)。

①原子性(undo log回滚保证事务的原子性):指同一对的事务操作,要么全成功,要么全失败,操作失败不能对数据库有影响。

②一致性(undo log+redo log保证事务一致性):事务操作之后,数据库内的数据总量保持一致。(能量守恒)

③隔离性(锁保证事务隔离性):相同的表,不同事务之间不能互相干扰。

④持久性(redo log重做日志用来保证事务持久性):事务一旦被提交,就需要在数据永久化存储,即便故障也不会丢失提交事务的操作。


MySQL怎么保证事务的特性的?

只有InnoDB存储引擎能保证事务特性。

为什么InnoDB能支持事务特性?

redo log重做日志用来保证事务的持久性:当commit时,必须先将事务的所有日志写到重做日志文件进行持久化,直到commit结束日志才算完成。

undo log回滚日志保证事务的原子性:事务完成前,操作并没有真正执行,而记录在日志中,undoglo会记录之前事务对应的行数据,回滚时,会根据日志进行反向操作,对中间记录的每一步操作进行逻辑删除,从而保证原子性。

undo log+redo log保证事务的一致性:操作过程中由redo log保证持久化,一但过程中出错,就由undo log回滚。

锁(共享、排他)用来保证事务的隔离性:事务的隔离性的实现原理就是锁,InnoDB主要有2种锁,行级锁跟意向锁。


事务的隔离级别有哪几种?

4种。

读未提交(RU:read uncommitted):可能存在【脏读+不可重复读+幻读】的问题。

读已提交(RC:read committed):可能存在【不可重复读+幻读】问题。

可重复读(RR:repeatable read):可能存在【幻读】问题。

串行化(serializable):无以上问题,但效率低,一务在分布式事务的情况下用该级别。


什么是脏读?幻读?不可重复读?

脏读(Drity Read):是指在一个事务处理过程中读取了另一个未提交的事务中的数据 , 导致两次查询结果不一致。

不可重复读(Non-repeatable read)【MySQL默认】:事务开启后关闭前,多次读取同一条记录,结果却不能保证一致,所以叫不可重复读。主要问题不在同一个数据库的问题,而在不同的服务器,不同数据库时会出现的问题,因为两台电脑之间要保证数据相同,是需要时间进行复制的,从表在复制主表的过程中,很可能因为修改数据过快而导致复制到错误数据。

幻读(Phantom Read):select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入。或不存在执行delete删除,却发现删除成功。

事务的隔离级别是怎么解决以上三种问题的?

解决脏读:修改时加排他锁(写锁),直到事务提交后才释放,读取时加共享锁(读锁),其他事务只能读取,不能再有更新操作。防止脏读。

解决不可重复读:innodb引擎采用了MVCC(多版本并发控制)来解决不可重复读问题。mvcc是利用在每条数据后面加了隐藏的两列(创建版本号和删除版本号)当执行查询的时, 当前查询版本号>= 创建版本号 并且 >删除版本号 , MVCC可以在大多数情况下代替行级锁,使用MVCC,能降低其系统开销。

解决幻读:采用next-key锁解决幻读问题,next-key锁包含两部分:记录锁(行锁)+间隙锁,就是在索引和索引之间上面加锁。


对MySQL的锁了解吗

​ 当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制。

就像酒店的房间,如果大家随意进出,就会出现多人抢夺同一个房间的情况,而在房间上装上锁,申请到钥匙的人才可以入住并且将房间锁起来,其他人只有等他使用完毕才可以再次使用。


隔离级别与锁的关系

在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突

在Read Committed级别下,读操作需要加共享锁,但是在语句执行完以后释放共享锁;

在Repeatable Read级别下,读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁。

SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。


按照锁的粒度分数据库锁有哪些?锁机制与InnoDB锁算法

​ 在关系型数据库中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 )。

MyISAM和InnoDB存储引擎使用的锁:

MyISAM采用表级锁。

InnoDB支持行级锁和表级锁,默认为行级锁


行级锁,表级锁和页级锁对比?

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

特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

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

特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。

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

特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。


从锁的类别上分MySQL都有哪些锁呢?像上面那样子进行锁定岂不是有点阻碍并发效率了

从锁的类别上来讲,有共享锁和排他锁。

共享锁: 又叫做读锁。 当用户要进行数据的读取时,对数据加上共享锁。共享锁可以同时加上多个。

排他锁: 又叫做写锁。 当用户要进行数据的写入时,对数据加上排他锁。排他锁只可以加一个,他和其他的排他锁,共享锁都相斥。

用上面的例子来说就是用户的行为有两种,一种是来看房,多个用户一起看房是可以接受的。 一种是真正的入住一晚,在这期间,无论是想入住的还是想看房的都不可以。

锁的粒度取决于具体的存储引擎,InnoDB实现了行级锁,页级锁,表级锁。

他们的加锁开销从大到小,并发能力也是从大到小。


MySQL中InnoDB引擎的行锁是怎么实现的?

答:InnoDB是基于索引来完成行锁

例: select * from tab_with_index where id = 1 for update;

for update 可以根据条件来完成行锁锁定,并且 id 是有索引键的列,如果 id 不是索引键那么InnoDB将完成表锁,并发将无从谈起


InnoDB存储引擎的锁的算法有三种

Record lock:单个行记录上的锁

Gap lock:间隙锁,锁定一个范围,不包括记录本身

Next-key lock:record+gap 锁定一个范围,包含记录本身

相关知识点:

innodb对于行的查询使用next-key lock

Next-locking keying为了解决Phantom Problem幻读问题

当查询的索引含有唯一属性时,将next-key lock降级为record key

Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生

有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock)
A. 将事务隔离级别设置为RC
B. 将参数innodb_locks_unsafe_for_binlog设置为1


什么是死锁?怎么解决?

死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。

表级锁不会产生死锁,行级锁和页级锁会产生死锁。

常见的解决死锁的方法:

1、如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。

2、在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;

3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;

如果业务处理不好可以用分布式事务锁或者使用乐观锁。

为什么表级锁不会产生死锁?

表级锁是锁住一个事务要用到的所有表,保证一个事务的完整性,而不只是指只给一张表上锁,所以整个事务的表都上锁的话,就不会有其他线程的干扰,也就不会产生死锁。


数据库的乐观锁和悲观锁是什么?怎么实现的?

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。实现方式:使用数据库中的锁机制

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。在修改数据的时候把事务锁起来,通过version的方式来进行锁定。实现方式:乐一般会使用版本号机制或CAS算法实现。

两种锁的使用场景

从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。

但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。


行级锁,表级锁和页级锁是悲观锁吗?

不一定。行级锁、表级锁和页级锁是按粒度来划分的,与是否是悲观锁没有直接关系。

排他锁是悲观锁,共享锁是乐观锁。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值