跳转至

MySQL 事务

事务特性#

  1. 原子性:数据库操作要么执行成功,要么执行失败回滚。

  2. 一致性:事务必须保证数据库从一个一致性状态到另一个一致性状态,比如说A,B一共有200元,在事务过程中,无论A、B怎么转账,A、B的还是一共有200元。

  3. 隔离性: 并行操作数据库的事务之间不能相互干扰, 即对于任意事务1,来说事务2要么在1之前完成,要么在1之后完成。

  4. 持久性:事务提交之后,数据肯定会被保存子在磁盘中。

隔离性解决的问题#

  1. 脏读: 事务1修改数据,之后事务1回滚。事务2在事务1 回滚之前修改数据之后,在此基础上对数据进行修改,之后提交事务。

  2. 不可重复读:解决脏读,事务1执行两次查询,在两次查询之间,事务2对查询的数据进行了修改(增、删、改),并提交了事务,导致事务1两次查询产生的结果不一样。

  3. 幻读:解决不可重复读,事务1执行两次查询一次操作,事务2在两次查询之间插入数据数据,由于不可重复度的原因,事务1第二次查到的数据和第一次查到的数据相同,但是事务1执行插入和事务2插入的数据相同数据时会失败。

事务隔离级别#

以A和B两个不同的事务为例,事务A读取数据,事务B更新数据,把事务B的执行分为4个阶段

1
`开始(S1) -> 第一次更新数据(S2-> 第二次更新数据(S3) -> 第三次插入一条数据(S4) -> 提交事务(S5)`
  1. Read Uncommit(读未提交):可能发生脏读、不可重复度和幻读。

    • 在此隔离级别下:事务B执行 S2 之后,事务A读取数据,会读取到事务B第一次更新后的数据,此时事务B还未提交,出现脏读的情况。
  2. Read Commit(读提交): 可避免脏读,可能发生不可重复度和幻读。

    • 在此隔离级别下:

      • 事务B执行 S2 之后,事务A读取数据,会读取到事务B开始时的原始数据,避免脏读的情况。
      • 事务B执行 S5 之后,事务A再次读取数据(事务A在第一次读取之后没有提交),此时读取的数据和第一次读取的数据不一致,出现了不可重复读的情况。
  3. REPEATABLE READ(可重复读):执行update更新语句时,会在更新时所有已提交的事务产生最新的记录上进行更新,有可能出现更新的实际内容和事务内查询出的内容不一致的情况。(InnoDB 通过版本解决幻读)。

    • 事务B执行 S2 之后,事务A读取数据,会读取到事务B开始时的原始数据,避免脏读的情况。
    • 事务B执行 S2 之后,事务A查询一次总数量。
    • 事务B执行 S5 之后,事务A再次读取数据(事务A在第一次读取之后没有提交),此时读取的数据和第一次读取的数据一致的,避免不可重复读的情况(快照机制)。
    • 事务B执行 S5 之后,事务A查询一次总数量,和前面查询结果相同,事务A执行一次 update all 操作,此时事务B提交的内容也会被更新(在所有已提交事务产生的最新版本的数据上进行更新),之后事务A再执行一次查询总数操作,此时查询的数量比前两次多一。

      START TRANSACTION;
      SELECT * FROM person;
      update person SET age = age + 1 WHERE name = 1;
      COMMIT;
      
      START TRANSACTION;
      SELECT * FROM person;
      update person SET age = age + 1 WHERE name = 1;
      COMMIT;
      

      上面两个事务不论以什么的顺序执行,全部提交之后,age的值会增加二,符合常理。

  4. SERIALIZABLE:串行执行。可避免脏读,不可重复读,幻读。

    • 所有的事务串行执行,由于同时只有一个事务执行,保证事务再执行的时候,没有其它事务会会影响次失的操作,效率很低。

MySql事务机制#

undo 日志#

记录执行的语句,在出错的时候进行数据回滚。回滚的时机:

  • 执行 rollback 回滚。
  • 数据库服务重启之后,回滚未完成的事务。