MySQL事务

Posted by Liao on 2020-05-13

事务

事务是由一组SQL语句组成的一个执行单元,该执行单元要么全部执行或全部不执行

事务四大特质(ACID)

  • 原子性(Atomicity):指事务包含的所有操作(sql)要么全部成功,要么全部失败回滚。事务是最小单位,不可再分。

    • 回滚通过undo log实现,回滚行记录到某个特定版本
    • undo log 记录的是逻辑操作日志(如对某行数据进行insert操作,那么undo log会记录一条与之相反的delete操作)
  • 隔离性(Isolation):事务A和事务B之间具有隔离性,一个事务在最终提交之前,对其它事务不可见。

    • 通过锁机制实现
  • 持久性(Durability):一旦事务提交,其所做的修改永远保存在数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。(内存的数据持久到硬盘文件中)

    • 系统发生崩溃可以通过重做日志(Redo log)进行恢复,从而实现持久性,是数据页的物理修改(页号、偏移量)。
    • 假设内存1s会一直做刷盘操作,若当发生宕机时,内存会把内存中的数据写入Redo log中,机器恢复之后,磁盘会从Redo log中获取数据,完成数据恢复
  • 一致性(Consistency):事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败。ACI为了一致性

    比如上一个事务中执行了第二步时系统崩溃了,数据也不会出现bill的账户少了100块,但是tim的账户没变的情况。要么维持原装(全部回滚),要么bill少了100块同时tim多了100块,只有这两种一致性状态的

并发问题

当要同时执行多个事务时,这些事务访问数据库中相同的数据时,如果没有相应的事务隔离级别,就会引发各种并发问题:

曾经被问过一个问题:如果有人同时新增预约系统的数据,有没有相应的措施?其实是在考数据库的并发问题啊

  • 脏读(未提交读)
    如2个事务T1、T2,如果T1读取了已被T2更新过但没有提交的字段之后,若T2回滚,T1读取的内容是暂时且无效的

  • 不可重复读

    如2个事务T1、T2,如果T1读取了一个字段,然后T2更新了该字段并提交之后,T1再次读同一个字段,值就不同了(重点是更新)

  • 幻读

    如2个事务T1T2,如果T1从数据表读了一个字段,然后T2在表中插入新的行,之后如果T1再读取同一个表,就会出现多了几行(重点是插入)

    解决:在可重复读隔离级别下,使用 MVCC + Next-Key Locks解决

MySQL的事务隔离级别

MySQL支持4种事务隔离级别,Oracle支持2种(Read Commit,Serializable)

  1. READ UNCOMMITED(读未提交数据)
  2. READ COMMITED(读已提交的数据)
  3. REPETABLE READ(可重复读) MySQL默认 解决了不可重复读、幻影读的问题,使用 MVCC + Next-Key Locks实现
  4. SERIALIZABLE(串行化) 锁