MySQL的事务和隔离级别实战
什么是事务?
每一个事务相当于对数据库进行操作的一个专用房间,在进入房间,操作数据库,离开房间的这期间所有操作需要符合ACID特性。所以,要了解事务,核心就是知道ACID特性意味着什么。
-
原子性(Atomicity):事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。回滚可以用回滚日志(Undo Log)来实现,如果是插入,根据日志里记录的主键ID把对应记录删除即可;如果是删除,把日志里记录的旧版本重新插入表中即可;如果是修改,用日志里记录的旧版本替换即可。
-
一致性(Consistency):从一个正确的状态到另一个正确的状态。关键在于什么是正确的状态?这个就是由两方面保证的,一个是数据库的约束(比如一致性约束,check约束等),另一个是业务约束,比如规定所有记录的余额之和不能大于100,这就需要业务代码保证。在《凤凰架构》、《数据密集型应用》等许多书籍资料中,都认为一致性应该完全是业务保证,并不是数据库保证,这就与其他三种特性形成鲜明对比。
-
隔离性(isolation):不同事务之间的读、写操作不会彼此影响。不过这与事务的隔离级别密切相关,事务的隔离级别决定了哪些情况不会彼此影响,哪些情况则不一定。
-
持久性(Durability):事务满足持久化是为了能应对系统崩溃的情况。一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。系统发生奔溃可以用重做日志(Redo Log)进行恢复,从而实现持久性。
事务的隔离级别
事务隔离就是为了解决脏读、不可重复读、幻读三种读取问题而提出的,不同隔离级别能解决不同程度的读取问题(可串行化>可重复读>读已提交>读未提交)。我们从一个例子就可以了解事务的四种隔离级别都能解决哪些场景下的读取问题。
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);
读取问题 | 事务A | 事务B |
---|---|---|
![]() | ![]() | |
![]() | ||
![]() | ||
如果是可串行化 | ![]() | |
出现脏读 | ![]() | |
![]() | ||
出现不可重复读 | ![]() | |
![]() | ||
![]() | ||
出现幻读 | ![]() |
-
脏读:在读未提交的隔离级别下出现,读已提交、可重复读下读取c的值为0,可串行化直接阻塞事务B更新操作的执行。
-
不可重复读:在读已提交以下的隔离级别出现,可重复读下读取c的值为0,可串行化直接阻塞事务B更新操作的执行。
-
幻读:在可重复读以下的隔离级别出现,且必须是当前读,可串行化则会在事务B想要执行插入操作的时候就阻塞。
如今互联网上各类文章满天飞,但是大部分要不是寥寥数语,让人过目即忘;要不是过多细枝末节又没有实操,让人不知所云。我将从个人学习和工作经历出发,给大家带来深入浅出的技术解析。我的文章力求简短精悍,尽量结合实战,以便大家在碎片时间即可充分吸收,后续还能学以致用。
欢迎大家关注我的微信公众号,所有文章第一时间更新~