Mysql事务原理与优化最佳实践
学习来源-图灵课堂
https://vip.tulingxueyuan.cn
说到MySQL的innodb的一大特性,就不得不说到事务。今天就学习事务。
事务
事务的定义:逻辑上的一组操作,要么一起成功,要么一起失败,中间绝对不会存在别的状态。逻辑上的一组操作,就是说这些操作都是有逻辑关系的。
我们通常说的事务是针对修改操作(新增,编辑,删除),但是查询操作也是可以加事务的。
事务有四大特性:ACID,就是所谓的原子性,一致性,隔离性,持久性。其中一致性是其它三个特性都满足之后才能实现的。
- 原子性(Atomicity) :当前事务的操作要么同时成功,要么同时失败,从效果上看一体的。原子性由undo log日志来实现。针对修改操作,undo log中会写入和其完全相反的一句SQL,便于rollback;rollback和commit是保证原子性的。
- 一致性(Consistent) :使用事务的最终目的,由其它3个特性以及业务代码正确逻辑来实现。
- 隔离性(Isolation) :在事务并发执行时,他们内部的操作不能互相干扰。隔离性由MySQL的各种锁以及MVCC机制来实现。
- 持久性(Durable) :一旦提交了事务,它对数据库的改变就应该是永久性的。持久性由redo log日志来实现。
并发事务带来的问题
- 更新丢失(Lost Update)或脏写:当两个或多个事务选择同一行数据修改,有可能发生更新丢失问题,即最后的更新覆盖了由其他事务所做的更新。
- 脏读(Dirty Reads):事务A读取到了事务B已经修改但尚未提交的数据,回滚之后数据无效。
- 不可重读(Non-Repeatable Reads):事务A内部的相同查询语句在不同时刻读出的结果不一致。主要是针对查询单条数据,别的事务可能对这行数据进行了修改。
- 幻读(Phantom Reads)或者是幻读:事务A读取到了事务B提交的新增数据。主要是读期间别的事务执行了插入操作。每次读取都能得到新的数据。
事务隔离级别
事务隔离级别是数据库本身提供的功能。都有其默认值,但是也可以进行修改的。可以根据业务需求去决定是否要修改默认的隔离级别。
|
隔离级别
|
脏读(Dirty Read) |
不可重复读 |
幻读(Phantom Read) |
|
读未提交(Read
uncommitted)
|
可能 | 可能 | 可能 |
|
读已提交(Read
committed)
|
不可能 | 可能 | 可能 |
|
可重复读
(Repeatable read)
|
不可能 | 不可能 | 可能 |
|
可串行化
(Serializable)
|
不可能 | 不可能 | 不可能 |
事务隔离级别越高,其安全性一致性就越好,但是相应的其执行效率就越低。
不同的业务场景针对事务隔离级别有要求,可以针对的进行设置。
MySQL默认的隔离级别是可重复读;Oracle默认的隔离级别是读已提交。
用Spring开发程序时,如果不设置隔离级别默认用数据库设置的隔离级别,如果Spring设置了就用已经设置的隔离级别。
事务隔离级别的具体实现
- 读未提交,没有进行任何额外处理,其数据库执行效率是最高的,但是其数据库安全性是最低的, 要在业务侧保证事务的执行。
- 读已提交,此时是读的当前,当前读就是时刻读取当前的最新已经提交的值。
- 可重复读,引入了MVCC和锁机制去保证。其中MVCC就用到了快照读,就是读的历史版本;锁机制,提高间隙锁等。
- 可串行化,是严格的加锁机制,读写互斥,写写互斥,读读不互斥。是类似Java的悲观锁。效率极其低下。
真实的数据只是会维护一份;不同线程的查询是通过整个版本链来查的。所有的查询修改共同构成这条数据的版本链。
每次数据的修改,都会有自己的一套版本链。查询的时候,就是通过可见性算法去定位到自己要查询的版本。
并不是多个快照,多个日志,多条真实数据;这样的话就太占用空间了。