mysql事务详解
目录
什么是事务
事务的四大特性
原子性
一致性
持久性
隔离性
什么是事务
在日常开发中,一个操作往往并不只涉及到一个单独的SQL,而是会涉及多个SQL一同完成.
比如转账这一操作,需要对转出的账户的余额减少相应的数字,对于转入的账户余额加上相应的数字.
一旦有一方没有正确操作,就出大问题了(血汗钱凭空消失了)!!!
这可能是源于系统崩溃,网络断开导致前面的SQL语句操作成功,后面的SQL语句操作失败.这是多个SQL同时操作会遇到的问题.而事务就是用来解决这种"中间状态引起的问题".
事务的四大特性
1.原子性
刚才我们提到转账这一个例子,如果把转出操作和转入操作作为一个整体,那么只能出现转出转入都成功或者转入转出都不成功的情况,并不会引起金额丢失/错误的严重后果.而事务也确实是这么做的.
事务,将多个操作打包成一个整体,要么这些整体都执行成功,要么都不成功,有效避免了部分执行成功,部分执行不成功的情况.这是原子性的体现,有种"不可分割"的感觉.
回滚机制
那么我们可能会有疑问:事务怎么会知道哪里会出现"中间状态引起的问题"的呢?
实际上我们不知道,它也不知道!!!SQL也是摸索前行!!!
SQL语句在事务中也是一条一条语句执行,当遇到这些"中间状态引起的问题"时,它可以通过之前记录的日志(记录到硬盘中)进行"回滚",例如之前进行了增加操作,现在就做对应的删减操作;之前进行了删减操作,现在就做对应的增加操作;之前进行了修改操作,现在就改回去;之前进行了查询操作,就不用操作.
进行完回滚之后,可以使SQL看起来"完好如初",但它也曾一条路走到黑再回首,并不是像神仙一样可以预知未来.
2.一致性
执行事务之前和执行事务完毕后,sql保证数据是一致的,是对于数据正确的承诺.
这也与回滚有关,一旦触发回滚,回滚回去的数据得是对的;如果执行顺利没有触发回滚,数据也要是符合要求的.
3.持久性
"持久性"我们可以简单地理解为:把数据存储在硬盘上.此处的"持久"要求,程序重启/主机重启,数据仍然存在.
这里内部的原理比较复杂,提交一个事务(事务执行完毕),背后一系列的内存/硬盘之间的交互联动,但是最终能够保证提交的事务一定会落实到硬盘上.
4.隔离性
隔离性相较于前三个特性,更加难以理解.它描述的是数据库在执行并发 事务时,产生的情况.所谓并发,就是多个客户端,同时发给服务器,发起事务.
每个客户端什么时候把事务提交过来?=>不知道!这就意味着很有可能出现多个客户端把事务一起提交过来的并发情况.一个一个事务处理,处理的速度会比较慢:但一起处理又容易出现问题.
并发处理可能出现的问题
- 脏读问题
- 不可重复读问题
- 幻读问题
1.脏读问题
让我们设置这么一个场景:
我和同桌一起在考试,我同桌有好多题目不会,就来看我的答案,看完以后抄到自己的试卷上.但是他看完之后,我又把答案给改了,这就导致他读到的答案和我最终试卷上的答案是不同的.
数据库中,事务A针对某个表进行了一些操作,在提交之前,事务B就对这个表中的数据进行了读取,导致最后B读到的数据和A提交的数据并不同,这就产生了脏读问题.
解决的方法也十分简单,就是对"写"这个操作进行加锁.我试卷上的答案在确定不更改之前,同桌不许偷偷看,在"写"这个操作完成之后再进行"读"操作,就可以解决脏读问题.
2.不可重复读问题
我同桌在我确定答案之后就变成了无情的"抄写机器",但是在他抄的过程中,我发现我有个地方写错了,就立即修改了答案,同桌抄着抄着发现答案突然就变了(因为我修改成了新的答案).开始是一份数据,结束的时候是另外一份数据.
事务A针对数据进行修改,提交;接下来事务B进行数据的读取(多个sql都要进行读取操作);在执行B的过程中,又有一个事务C对数据进行了更改.这就产生了不可重复读问题.
这个问题的解决也并不复杂,给"读"这个操作也加锁就可以了.我同桌说"我抄的时候你不许动笔再改答案了".
3.幻读问题
这时,我说"好,我不改答案了,我在卷子上画小人玩总可以吧";这时虽然我卷子上的答案没有改变,同桌也全抄上去了,但是同桌已经"抄傻了",把我画的小人也抄上去了!!!
事务A先修改并提交数据,事务B进行读数据,此时事务C没有修改B的数据,但是给对应的表进行了新增/删除数据的操作,导致B读到的数据集不同.这就产生了幻读问题-已有的数据内容一致,数据的条数增加/减少,可以视为特殊的"不可重复问题".
要解决幻读问题,可以使用"串行化"."串行化"使得所有事务严格按照"一个接一个"的方式执行.
我们来分析以上三种问题的解决方法.
- 对于脏读问题=>"写加锁",会导致"读操作"需要一定的等待时间,降低了并发性.
- 对于不可重复读问题=>"读加锁",会导致"写操作"需要一定的等待时间,再次降低了并发性.
- 对于幻读问题=>"串行化",完全牺牲了并发性.
对于数据库,数据的安全.准确比所谓的效率更加重要,因此内部通过牺牲并发/效率来保证数据的安全.
mysql事务隔离性的体现
mysql给程序猿提供了四个隔离级别,可以在mysql配置文件中进行设置.
- read uncommited:允许读取未提交的事务的数据 => 存在 脏读+不可重复读+幻读 问题
- read commited:只允许读取提交的事务的数据 => 存在 不可重复读+幻读 问题
- repeatable read:写加锁+读加锁 => 存在 幻读 问题
- serializable:串行化 => 十分安全
上面四种隔离级别,并发性从上到下依次递减,安全性从上到下依次递增.