mysql事务 | 青训营笔记

45 阅读6分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天

一、事务相关概念

事务概念:

什么是事务

事务就是一条或多条需要执行的语句,在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元。在编程语言java和c等中,可以用begin transaction开启事务和end transaction之类的进行界定,包括在这两条语句中的操作看作一条事务。

对于Mysql数据库来看,事务是通过start transaction开始,到执行commit和rollback命令结束的全部sql语句。在没有出现异常错误等情况时候通过commit进行提交事务,改变数据库中的数据项,当异常错误等情况发生的时候通过rollback方式进行回滚事务,表示事务执行失败,看作该事务的所有语句都不发生执行。回到start transaction时候的状态。

目前mysql中室友InnoDB和NDB支持事务,这也是为什么innoDB超过Myisam的原因之一。

InnoDB引擎为例,默认开启autocommit配置,也就是自动提交事务,意为每条sql语句看作一个事务。关闭autocommit通过,set autocommit=0,这个是对于每条数据库连接生效的,不会对其他连接生效。关闭自动提交后,需要使用commit和rollback执行事务,在这时开启另一个新的事务。

特别的在一些数据库语句中回自动进行commit提交事务。DDL语句(create table/drop table/alter table),lock tables等。常用的select、insert、update、delete不会进行强制提交事务。

ACID

a(Atomicity)原子性,c(Consistency)一致性,i(Isolation)隔离性,d(Durability)持久性

按照严格要求,ACID特性才是事务,但是,少有数据库实现了这四个特性。

A原子性

事务作为原子就是不可分割开的,原子性事务提交要么成功,要么失败

实现原理:undo log

语句执行成功好说,要是执行失败就需要undo log进行处理。undo log保证了原子性和隔离性实现的基础。InnoDB实现回滚,靠undo log:当事务对数据库进行修改时候,生成undolog。实行失败执行rollback时候,根据undolog中记录的信息进行回滚。

C一致性

事务开始和结束后,数据库约束没有被破坏,也就是逻辑关系合理,满足约束条件。通过原子性持久性隔离性保障数据库的状态。

I隔离性

事务之间不能够互相干扰,一个事务不能看到其它事务的中间状态。也就是某一些数据

  • 一个事务写操作对另一个事务写操作的影响:锁机制保证隔离性
  • 一个事务写操作对另一个事务读操作的影响:MVCC保证隔离性

锁:事务在修改数据之前需要获得锁

分类:

  • 按照粒度分
    • 表锁,MyIsam只支持这个。InnoDB支持这个
    • 行锁,InnoDB支持这个

表锁表示,操作数据时候,回导致整张表的上锁。并发性能较差。行锁表示,操作数据时候,只会给当前操作的行进行上锁,并发性能好。由于上锁本来就会花费资源,当出现大量的行锁时候,通过表锁可以节约资源。

D持久性

事务一但提交成功处于合法状态,事务的操作都被保存在数据库中,不会被回滚。

实现原理:redo log

前提:数据存储在磁盘上,每次读写数据需要磁盘IO,导致效率低。为此InnoDB提供缓存(Buffer Pool),对数据的读写后实在BufferPool中进行的。写的时候,现在BufferPool中进行了修改,但是没有修改磁盘而是之后更新磁盘,这过程称为“刷脏”

问题:如果BufferPool中的数据在没有更新到磁盘上的时候出现断电,持久性就被破坏了,redo log用来处理这个过程。事务提交最先通过fsync接口对redolog进行刷盘,redolog中存储了数据。然后再更新BufferPool,这个时候断电,redolog中已经记录了数据,下次开机重新执行redolog就能够保证数据持久性。

问题:redolog能够写入磁盘,会比BufferPool快吗?

  • redolog是顺序IO也就是在文件后追加,而BufferPool是随机IO也就是文件中修改。
  • 刷脏以数据页为单位,Mysql一页16KB,而redolog只是很小的一部分数据,大大减少了IO

脏读,不可重复读,幻读

概念

脏读:事务A读取到事务B没有提交的数据,这种现象就是脏读

不可重复读: 事务A两次读取结果不同。前一次读取的数据,被修改后再被读就不一样。

幻读:两次查询数据库,结果数量不同就是幻读。是数据量变换,不是内容变化。

事务隔离级别

读未提交(Read Uncommitted):脏读不可重复读幻读都不能避免。

读已提交(Read Committed):脏读能避免,不可重复读幻读不可以避免。

可重复读(Repeatable Read):脏读不可重复读能够避免,幻读不能避免。

可序列化(Serializable):脏读不可重复读幻读都能避免。

大多数数据库支持可重复读。InnoDB就是支持这个,然而InnoDB还解决了幻读。通过的是MVCC策略解决的。

MVCC

Multi-Version Concurrency Control,即多版本并发控协议。

读写不冲突,并发性能好,依赖于隐藏列和undo log。隐藏列包括版本号,删除时间,指向undolog的指针。读取数据mysql通过通过隐藏列判断是否需要回滚然后找到undo log实现MVCC。隐藏列的功能如下:通过判断不同的版本号,利用undolog进行处理。

  • 脏读:

通过判断是否被修改和未提交状态,然后通过undolog获取以前数据。

  • 不可重复度

通过判断版本号获取是否进行了修改(导致版本号改变),修改了就undolog获得以前的数据。

  • 幻读

通过锁定本条记录,还锁定范围空间,通过版本号的方式锁定的。这样就有回滚依据,避免幻读。

  • 由于处理幻读的方式不是serilizable所以还有一些缺陷。