本文是笔者对事务的理解,如有理解错误的地方,欢迎大家指正。
提到MySQL肯定要说事务,那么事务的ACID原则肯定是重点,事务的ACID原则我个人理解是
A:原子性,事务是一个整体不可以再切分,一个事务要么全部成功,要么全部失败,比如说转账这一件事,扣钱与加钱的操作应该是一个事务,否则就可能发生因为加钱服务因为自身故障导致扣钱没有加钱成功的事情发生。
C:一致性,数据流动应该是同步的,你的账户转出去了,肯定有人的账户要加
I:隔离性,事务之间不应该互相干扰,数据库有隔离级别设置,也是我后面写的重点
D:持久化,数据库的变化应该是永久性保存,刷入硬件上面,不会因为数据库故障而影响
好的架构不是设计出来的,而是逐渐演变过来的,所有的事情都是有发展的,每一个原则的诞生都是为了解决前面遇见问题,当我们把操作数据库时,前面操作数据有问题,导致后面操作有问题,我们就想把这一次操作看成一个整体,一次性回滚,回到操作前的状态,毕竟一个一个操作回滚太废时间了,这个时候我们就需要数据库的原子性原则,把这一个操作看成一个整体,数据库把数据回滚。
有了原子性原则,我们就可以在出错时进行操作了,什么情况下会出错呢,数据变化时,由于某些业务要求多个数据同步变化,把人口作为一个数据库,出生人口、存活人口、总人口、死亡人口都要做纪录(计算机好像一开始就是去做人口普查的,IBM发家史有兴趣可以百度一下),人在出生时,出生人口数据肯定要增加,总人口要变化,存活人口也要进行增加。如果存活人口与死亡人口加起来不等于总人口,肯定是数据出错误了,数据要进行回滚,回滚到那个存活人口与死亡人口加起来等于总人口的时间。对于数据一致性我理解应该划分为:
强一致性:读操作可以立即读到提交的更新操作。
弱一致性:提交的更新操作,不一定立即会被读操作读到,此种情况会存在一个不一致窗口,指的是读操作可以读到最新值的一段时间。
最终一致性:是弱一致性的特例。事务更新一份数据,最终一致性保证在没有其他事务更新同样的值的话,最终所有的事务都会读到之前事务更新的最新值。如果没有错误发生,不一致窗口的大小依赖于:通信延迟,系统负载等。
其他一致性变体还有:
单调一致性:如果一个进程已经读到一个值,那么后续不会读到更早的值。
会话一致性:保证客户端和服务器交互的会话过程中,读操作可以读到更新操作后的最新值。
由于业务要求一致性不同,导致事务之间如果并发执行就会存在一致性的问题,所以我们需要把事务进行分隔开,这时就需要隔离级别,事务之间不应该互相干扰,我们应该进行设置隔离级别,数据库内置了隔离级别。
Mysql事务隔离级别
余额宝减少,余额增加为一个事务
(1)读未提交
①A在手机A去余额宝里面查当前余额,B在手机B去余额宝里面申请转出100块,
②A查看余额是少了100块钱,B由于账户原因转出失败,申请被打回来,余额宝里面的钱还是没有变化的,A看到了错误的数据(脏读)
(2)读已提交
①A在手机A去余额宝里面查当前余额,B在手机B去余额宝里面申请转出100块
②B申请通过了,A去消费用余额宝,扣款时,因为B把钱转走了,所以扣款不成功,在A余额宝过程中,数据不可重复读
(3)可重复读
①A在手机A去余额宝里面查当前余额,B在手机B去余额宝里面申请转出100块
②B不允许转出,因为A正在买单去消费
(4)串行化
①一个一个事务来
因为隔离级别都是为了解决这3个问题:幻读,脏读,不可重复读
幻读,脏读,不可重复读
(1)幻读
①程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(全表扫描FTS,妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。
(2)脏读
①A查看余额是少了100块钱,B由于账户原因转出失败,申请被打回来,余额宝里面的钱还是没有变化的,A看到了错误的数据(脏读)
(3)不可重复读
①一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读
数据都处理完了,我们就需要把数据存储下来,如果存在内存中,电脑一故障,数据就全没有了,不符合我们要的,我们需要可以恢复,什么时候都可以看,而且不占过多的内存。操作的数据要完整存入数据库,这时我们就需要数据库持久化原则,如果操作数据没有存下来,那就告诉应用程序存取设备,回滚事务。这个时候就诞生的一个新问题,哪一个事务去存,我们就需要锁机制了。