面试官问你:MySQL事务和隔离级别,该如何回答

clipboard.png

1、事务

事务是由一组SQL语句组成的逻辑处理单元,是知足 ACID 特性的一组操做,能够经过 Commit 提交一个事务,也可使用 Rollback 进行回滚。事务具备如下4个属性,一般简称为事务的ACID属性:java

  • 原子性(Atomicity):事务是一个原子操做单元,其对数据的修改,要么全都执行,要么全都不执行。好比在同一个事务中的SQL语句,要么所有执行成功,要么所有执行失败。回滚能够用日志来实现,日志记录着事务所执行的修改操做,在回滚时反向执行这些修改操做便可。
  • 一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着全部相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,全部的内部数据结构(如B树索引或双向链表)也都必须是正确的。 以转帐为例子,A向B转帐,假设转帐以前这两个用户的钱加起来总共是2000,那么A向B转帐以后,无论这两个帐户怎么转,A用户的钱和B用户的钱加起来的总额仍是2000,这个就是事务的一致性。
  • 隔离性(Isolation):数据库系统提供必定的隔离机制,保证事务在不受外部并发操做影响的“独立”环境执行。 隔离性是当多个用户并发访问数据库时,好比操做同一张表时,数据库为每个用户开启的事务,不能被其余事务的操做所干扰,多个并发事务之间要相互隔离。即要达到这么一种效果:对于任意两个并发的事务 T1 和 T2,在事务 T1 看来,T2 要么在 T1 开始以前就已经结束,要么在 T1 结束以后才开始,这样每一个事务都感受不到有其余事务在并发地执行。
  • 持久性(Durable):事务完成以后,它对于数据的修改是永久性的,即便出现系统故障也可以保持。  能够经过数据库备份和恢复来实现,在系统发生奔溃时,使用备份的数据库进行数据恢复。
MySQL 默认采用 自动提交模式。也就是说,若是不显式使用 START TRANSACTION 语句来开始一个事务,那么每一个查询都会被当作一个事务自动提交。

clipboard.png

这几个特性不是一种平级关系程序员

  • 只有知足一致性,事务的执行结果才是正确的。
  • 在无并发的状况下,事务串行执行,隔离性必定可以知足。此时要只要能知足原子性,就必定能知足一致性。
  • 在并发的状况下,多个事务并发执行,事务不只要知足原子性,还须要知足隔离性,才能知足一致性。
  • 事务知足持久化是为了能应对数据库奔溃的状况。

2、并发一致性问题

Ⅰ、更新丢失(Lost Update)

T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改数据库

例如,两个程序员修改同一java文件。每程序员独立地更改其副本,而后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改副本的编辑人员覆盖前一个程序员所作的更改。数据结构

若是在一个程序员完成并提交事务以前,另外一个程序员不能访问同一文件,则可避免此问题并发

clipboard.png

Ⅱ、脏读

一句话:事务B读取到了事务A已修改但还没有提交的的数据,还在这个数据基础上作了操做。此时,若是A事务回滚Rollback,B读取的数据无效,不符合一致性要求。性能

解决办法: 把数据库的事务隔离级别调整到 READ_COMMITTED学习

T1 修改一个数据,T2 随后读取这个数据。若是 T1 撤销了此次修改,那么 T2 读取的数据是脏数据spa

clipboard.png

Ⅲ、不可重复读(Non-Repeatable Reads)

在一个事务内,屡次读同一个数据。在这个事务尚未结束时,另外一个事务也访问该同一数据。那么,在第一个事务的两次读数据之间。因为第二个事务的修改,那么第一个事务读到的数据可能不同,这样就发生了在一个事务内两次读到的数据是不同的,所以称为不可重复读,即原始读取不可重复。3d

一句话:一个事务范围内两个相同的查询却返回了不一样数据日志

同时操做,事务1分别读取事务2操做时和提交后的数据,读取的记录内容不一致。不可重复读是指在同一个事务内,两个相同的查询返回了不一样的结果

解决办法: 若是只有在修改事务彻底提交以后才能够读取数据,则能够避免该问题。把数据库的事务隔离级别调整到REPEATABLE_READ

T2 读取一个数据,T1 对该数据作了修改。若是 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不一样

clipboard.png

Ⅳ、幻读

一个事务T1按相同的查询条件从新读取之前检索过的数据,却发现其余事务T2插入了知足其查询条件的新数据,这种现象就称为“幻读”。(和可重复读相似,可是事务 T2 的数据操做仅仅是插入和删除,不是修改数据,读取的记录数量先后不一致)

一句话:事务A 读取到了事务B提交的新增数据,不符合隔离性。

解决办法: 若是在操做事务完成数据处理以前,任何其余事务都不能够添加新数据,则可避免该问题。把数据库的事务隔离级别调整到 SERIALIZABLE_READ。

T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不一样

clipboard.png

3、事务隔离级别

"脏读"、"不可重复读"和"幻读",其实都是数据库读一致性问题,必须由数据库提供必定的事务隔离机制来解决

数据库的事务隔离越严格,并发反作用越小,但付出的代价也就越大,由于事务隔离实质上就是使事务在必定程度上 “串行化”进行,这显然与“并发”是矛盾的。同时,不一样的应用对读一致性和事务隔离程度的要求也是不一样的,好比许多应用对“不可重复读”和“幻读”并不敏感,可能更关心数据并发访问的能力。

MYSQL常看当前数据库的事务隔离级别:show variables like 'tx_isolation';

Ⅰ、读未提交 (Read Uncommitted)

最低的隔离等级,容许其余事务看到没有提交的数据,会致使脏读。

Ⅱ、读已提交 (Read Committed)

被读取的数据能够被其余事务修改,这样可能致使不可重复读。也就是说,事务读取的时候获取读锁,可是在读完以后当即释放(不须要等事务结束),而写锁则是事务提交以后才释放,释放读锁以后,就可能被其余事务修改数据。该等级也是 SQL Server 默认的隔离等级。

Ⅲ、可重复读(Repeatable Read)

全部被 Select 获取的数据都不能被修改,这样就能够避免一个事务先后读取数据不一致的状况。可是却没有办法控制幻读,由于这个时候其余事务不能更改所选的数据,可是能够增长数据,即前一个事务有读锁可是没有范围锁,为何叫作可重复读等级呢?那是由于该等级解决了下面的不可重复读问题。(引伸:如今主流数据库都使用 MVCC 并发控制,使用以后RR(可重复读)隔离级别下是不会出现幻读的现象。)

MYSQL默认是REPEATABLE-READ

Ⅳ、串行化(Serializable)

全部事务一个接着一个的执行,这样能够避免幻读 (phantom read),对于基于锁来实现并发控制的数据库来讲,串行化要求在执行范围查询的时候,须要获取范围锁,若是不是基于锁实现并发控制的数据库,则检查到有违反串行操做的事务时,需回滚该事务。

Ⅴ、总结

  • 读未提交: 一个事务还没提交时,它作的变动就能被别的事务看到
  • 读提交: 一个事务提交以后,它作的变动才会被其余事务看到。
  • 可重复读 : 一个事务执行过程当中看到的数据,老是跟这个事务在启动时看到的数据是一致的。固然在可重复读隔离级别下,未提交变动对其余事务也是不可见的。
  • 串行化: 顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

四个级别逐渐加强,每一个级别解决一个问题,事务级别越高,性能越差,大多数环境(Read committed 就能够用了)

隔离级别 读数据一致性 脏读 不可重复读 幻影读
未提交读 最低级别
提交读 语句级 ×
可重复读 事务级 × ×
可串行读 最高级别,事务级 × × ×

写在最后

  • 第一:看完点赞,感谢您对做者的承认;
  • ...
  • 第二:随手转发,分享知识,让更多人学习到;
  • ...
  • 第三:记得点关注,天天更新的!!!
  • ...
相关文章
相关标签/搜索