Mysql事务是后端开发中经常用到的知识点,很多同学都会比较浅的了解事务的特性和基本原理就进行开发,但并没有深入的进行多各种隔离方式的实践,往往会在多线程处理的时候就会掉进坑里。今天我们就一起深入实践,还原每一个场景。
目录什么是事务?
事务的特性
多个事务并发会出现什么问题?
事务的几种隔离级别
事务隔离级别的实现原理
什么是事务?事务是数据库一个有限的操作序列,这些操作要么全部执行,要么全部不执行。举个例子:银行的用户A账户余额有块,这时候用户A要转账块给用户B,银行已经把A的余额扣除了,但突然银行系统出错了,并没有把块转到用户B的账户上。这种情况这块就凭空消失了,当然是大家都不能接受的,所以银行就会一个回滚机制,把块退回到用户A的账户上。这就是事务,A的块要不成功转账给B,要不就退回给A,并不会凭空消失。
事务的特性从上面的例子其实就能反应出事务的4个特点:
原子性原子性指的就是事务中一系列的操作要不全部执行,要不全部不执行。在刚刚例子中,如果用户A同时转账50给用户B和用户C,要不都转账成功,用户B、C各收到50块。要不银行把2个50块都退回给用户A,用户A账户余额还是块。
一致性一致性指的是在事务开始前和事务操作之后数据是不被破坏的。在刚刚例子中,不管怎么转账,对于用户A、B、C来说他们手上的总金额都是,不会凭空消失。
隔离性隔离性指的是多个事务并发访问的时候,他们之间是相互隔离的,一个事务不会被其他事务干扰。例如用户B在查看余额的时候,看到的是0块。这时候同时用户A给B转账了块,B看到的依然是0块,要等到B完成查看后A的块成功转账后再次查看才能看到B账户里面多了块。(这里是用了串行化的隔离级别,后面会对各种隔离级别进行介绍,不同的隔离级别会出现不同的效果)
持久性持久性指的是事务完成提交后,所有对数据库的操作都会被永久保存在数据库中。
多个事务并发会出现什么问题?刚刚不是说事务有隔离性吗?事务之间互不干扰,那为什么多个事务并发的时候还会出现问题呢?嗯,在一开始学习的时候,我也有这个疑问。其实可以理解为事务最终要实现的是这4大特性,而为了实现这4大特性的我们需要如何设计?我们需要抱着这个思路进行思考。在单线程中一个事务我们只要考虑原子性和一致性就可以了,要不全部执行,要不都不执行,且数据前后是一致的。但我们实践中基本都是多线程并发的,那在隔离性的实现上就会出现以下问题:
脏读例如:
用户A准备查询自己账户的余额(块)
同时用户B给用户A转账50块(未提交)
最终用户A查询到自己的余额是块
实际用户A的账户只有块,用户A事务查询到时候已经被用户B的事务影响到了
不可重复读例如:
用户A查询自己账户的余额(块)
同时用户B给用户A转账50块(已提交)
用户A再查询自己账户的时候余额变成了块
这次实际用户A的余额的确是块了,但在用户A的事务里面两次的查询金额应该是一致的才对,现在就是被用户B的事务影响到了。
幻读例如:
用户A查询自己有多少条收入记录,查询到了有2条
同时用户B给用户A转账50块(已提交)
用户A再查询自己有多少条收入记录时,查询到了有3条记录
用户A在事务中第一次查询了一个结果集,但在用户B的事务中插入了记录导致用户A第二次查询的时候结果集不一样了。
有没有发现不可重复读和幻读很像?都是在一个事务内查询了2次,这里很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
事务的几种隔离级别那上面提到在并发时候有可能出现的脏读、不可重复读、幻读3个问题,InnoDB到底是怎样解决的呢?下面我们一起到mysql设置不同的事务隔离级别进行实践,看看是如何解决的。
下面是事务的4个隔离级别:
-读未提交(read-un