1.事务
1.1 事务的定义和作用
- MySQL事务主要用于处理操作量大和复杂度高的数据。
- 在 MySQL中只有Innodb存储引擎的表才支持事务。
- 事务用来管理insert,update,delete语句。
1.2 事务的特性
- 原子性:一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。因此如果事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
- 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行而导致数据的不一致。
- 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
1.3 Mysql怎么保证原子性
- 是利用undo log来实现。当事务回滚时能够撤销所有已经成功执行的sql语句。undo log 需要记录要回滚的相应信息,当事务执行失败或者调用rollback语句时,便可以利用undo log中的信息将数据回滚到之前的状态。
1.4 Mysql怎么保证一致性
- 从数据库层面,数据库通过原子性、隔离性、持久性来保证一致性。也就是说,原子性、隔离性、持久性是数据库实现一致性的前提。例如,原子性无法保证,显然一致性也无法保证。
- 从应用层面,通过代码判断数据库数据是否有效,然后决定回滚还是提交数据。
1.5 Mysql怎么保证隔离性
- 利用的是锁实现。一个行数据有多个版本快照数据,这些快照数据存储在undo log中。如果一个事务读取的行正在做delete或者update操作,读取操作不会等待锁释放,而是读取该行的快照版本。
1.6 Mysql怎么保证持久性
- 利用redo log实现。和undo log相反,redo log记录的是新数据的备份。在事务提交前,只需要将redo log持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是redo log已经持久化。系统可以根据redo log的内容,将所有数据恢复到最新的状态。
- innodb_flush_log_at_trx_commit的值:
1.7 事务的隔离级别
- 读未提交:一个事务可以读取另一个未提交事务的数据。
- 读已提交:一个事务要等另一个事务提交后才能读取数据。
- 可重复读:并发执行的事务不会相互影响,其对数据库的影响和它们串行执行时一样。
- 序列化:最高的事务隔离级别。在该级别下,事务顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较消耗数据库性能,一般不使用。
- 值得一提的是:大多数数据库默认的事务隔离级别是读已提交,比如Sql Server , Oracle。Mysql的默认隔离级别是可重复读。
1.8 脏读、不可重复读和幻读
- 脏读:简单来说,就是一个事务在处理过程中读取另外一个事务未提交的数据。这种未提交的数据我们称之为脏数据,依据脏数据所做的操作是不正确的。
- 不可重复读:指一个事务范围内,多次查询某个数据,却得到不同的结果。
- 幻读:是事务非独立执行时发生的一种现象。
- 不同隔离级别产生不同的并发异常。
2.锁机制
2.1 行锁之行锁、间隙锁和Next-Key锁
- 行锁:单个行数据上锁。
- 间隙锁:锁定一个范围,但不包括记录本身,是为了防止幻读以及防止间隙内有新数据插入。
- Next-Key锁:锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。InnoDB默认加锁方式是next-key锁。
- 以上三种锁都是排它锁。
2.2 表锁之意向锁和自增锁
- 意向锁:InnoDB存储引擎引入了意向锁,意向锁就是一种表锁,允许行锁与表锁共存。实际应用中,InnoDB使用的是意向锁。意向锁是指,未来的某个时刻,事务可能要加共享/排它锁,先提前声明一个意向。
- 自增锁:如果存在自增字段,MySQL会维护一个自增锁,和自增锁相关的一个参数为
innodb_autoinc_lock_mode
,可以设定3个值0,1和2。
9.3 锁的具体实现之排它锁和共享锁
- 排它锁:又称为写锁。允许获得排它锁的事务更新数据,但是阻止其它事务取得排它锁。例如,事务T对数据对象A加上排它锁,事务T可以对对象A进行修改,但是其它事务不能对A进行修改。
- 共享锁:又称为读锁。允许一个事务读取一行,阻止其它事务进行修改。例如,事务T对数据对象A加上共享锁,其他事务只能对A再次加上共享锁而不能加排它锁,这保证其他事务可以读取A,但是T释放A的共享锁之前不允许对A做任何修改。
9.4 乐观锁和悲观锁
- 悲观锁:当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。悲观锁主要分为共享锁和排他锁。
- 乐观锁:乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测。如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场景,这样可以提高程序的吞吐量。
3.常见的存储引擎
3.1 INNODB存储引擎
- InnoDB具有较强的事务处理能力及较好的事务安全性并且支持外键,给MySQL提供了事务提交、回滚、崩溃修复能力、还能够实现并发控制下的事务安全,在需要频繁的更新、删除操作并要求事务完整性的情况下应该选择InnoDB种存储引擎。但是这种引擎不足之处是读写效率稍差,占用空间相对较大。
3.2 MyISAM存储引擎
- MyISAM存储引擎的表存储成三个文件。文件的名字与表名相同,扩展名包括
frm、MYD 和MYI
。其中,frm为文件存储表的结构;MYD为文件存储数据,其是MYData
的缩写;MYI为文件存储索引,其是MYIndex的缩写。基于MyISAM存储引擎的数据库支持三种不同的存储格式:静态、动态和压缩。其中前两个(静态格式和动态格式)根据正在使用的列的类型来自动选择,第三个即已压缩格式,只能使用myisampack工具来创建。
3.3 MEMORY存储引擎
- MEMORY存储引擎是MySQL中的一类特殊的存储引擎,它使用存储在内存中的内容来创建表,而且所有数据也放在内存中。其特点是访问速度快,但安全上没有保障,适用应用中涉及数据比较小、需要进行快速访问的场合。每个基于MEMORY存储引擎的数据库实际对应一个磁盘文件,该文件的文件名与表名相同,类型为frm类型,该文件中只存储表的结构,而数据文件都是存储在内存中。这样有利于对数据的快速的处理,提高整个表的处理效率。值得注意的是,服务器需要有足够的内存来维持MEMORY存储引擎的表的使用。如果不需要使用可以释放这些内存,甚至可以删除不需要的表。
3.4 INNODB存储引擎和MyISAM存储引擎的区别
- innodb支持事务和外键,而myisun不支持。
- innodb支持行锁和表锁,而myisum只支持表锁。
- 在mysql5.6版本之后,支持全文索引。
- innodb的叶子节点直接存储数据本身,而myisum存储的是数据的地址。
4.事务相关面试题
1.如何在可重复读级别解决幻读
- MVCC机制表面上可以解决幻读。
- 如果从根本上解决幻读,可以使用以下方法:a.使用序列化的隔离级别;b.
MVCC+next-key锁
:next-key锁由record locks(行锁) 和 gap locks(间隙锁,每次锁住的不光是需要使用的数据,还会锁住这些数据附近的数据)组成。 - 实际上很多的项目中是不会使用到上面的两种方法的,序列化的性能太差,而且其实幻读很多时候是我们完全可以接受的。