事务的特性ACID

  • 原子性(atomicity):事务的每一个写操作都是原子性的,要么一起成功,要么一起失败。要么全部提交成功,要么全部回滚
  • 一致性(consistency):先举例子,银行转账
    2、MySQL事务和多版本并发控制
    数据库总是从一个一致性的状态转换到另一个一致性的状态。当第3行执行结束后,开始执行第4行的时候,系统崩溃了,上一个账户还是没有减少200块,因为事务没有提交。回滚事务
  • 隔离性(isolation): 一个事务在提交前,对另外一个事务是不可见的,隔离的。详见事务的隔离级别。
  • 永久性(durability):一个事务提交后,就会永久保存到数据库中。

事务冲突后,会回滚修改行数较小的事务。

事务的隔离级别

  • 读未提交(read-uncommitted)
    一个事务未提交,另一个事务可以读到另外一个事务的脏数据。称为脏读

  • 不可重复度(read-committed) 或者是叫 读已提交。就是读取到的两次数据不一致。
    1)打开一个客户端A,并设置当前事务模式为read committed(读已提交),查询表account的所有记录:
    2、MySQL事务和多版本并发控制
    2)在客户端A的事务提交之前,打开另一个客户端B,更新表account,金额减去50块。
    2、MySQL事务和多版本并发控制
    3)B客户端的事务未提交,这时A看到账户里的钱还是 450,客户端A不能查询到B已经更新的数据,解决了脏读

2、MySQL事务和多版本并发控制

4)客户端B提交事务后,客户端A读到的数据成了400,两次读的数据不一样,所以不能重复读。
2、MySQL事务和多版本并发控制

  • 可重复读(repeatable-read)
    当隔离级别设置为可重复读的时候,在第四部查询的结果相同了
    1)打开一个客户端A,并设置当前事务模式为repeatable read,查询表account的所有记录
    2、MySQL事务和多版本并发控制
    2)在客户端A的事务提交之前,打开另一个客户端B,更新表account并提交
    2、MySQL事务和多版本并发控制
    3)在客户端A查询表account的所有记录,与步骤(1)查询结果一致,没有出现不可重复读的问题
    2、MySQL事务和多版本并发控制
    4)在客户端A,接着执行update balance = balance - 50 where id = 1,balance没有变成400-50=350,lilei的balance值用的是步骤(2)中的350来算的,所以是300,数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。

2、MySQL事务和多版本并发控制

  • 串行化(serializable)

  • 总结:事务的隔离级别越高,性能越慢。

mvcc多版本并发控制(存储引擎层面实现Innodb)

MySQL的事务型存储引擎,并不是通过简单的行级锁来处理并发的,而是通过MVCC,MVCC是行级锁的一个变种,只是在必要的时候,加上锁。

mysql中的mvcc在 可重复读(repeatable-read)的隔离级别下是如何工作的。
mvcc是在数据列后面加了2个隐藏的列:一个是创建时间,一个是过期时间(或删除时间)。创建时间是当前的版本号,每开启一个事务,版本号+1,

  • select:
    A:查询创建时间比当前版本号小的。这样就可以确保事务读取的行,要么是在事务开始之前就已经存在的,要么是当前事务本身增加的。
    B:行的删除版本号,要么是空的,要么是大于当前版本号的。这样就可以确保事务读取到的行,在事务开始之前未被删除。

    只有符合上面两个条件的记录,才能被返回。

  • insert: Innodb为新插入的每一行,保存当前系统版本号+1 ,为该行的创建时间版本号

  • delete: innodb为删除的每一行,保存当前的系统版本号+1,为该行的删除时间版本号

  • update:innodb 会插入一条修改后的记录,当前系统版本号+1为改行的创建时间版本号,同时保存当前的版本号+1 为原来的行作为删除时间版本号

相关文章: