mysql8.0

**

MySQL——事务

**

事务是研究MySQL其他高级特性前要知道的概念


文章目录

  • MySQL——事务
  • 事务的概念
  • 事务的标准特征
  • 隔离级别
  • MySQL中事务
  • 多版本并发控制


事务的概念

一般来说,事务就是一组原子性的SQL查询,或者说一个独立的工作单元。

如果数据库引擎能够成功应用该组查询的全部语句,就会执行改组查询。
如果有其中一条语句崩溃或其他原因无法执行,则该组都不会执行。

也就是说事务的语句要么全部执行成功,要不全部失败。

银行转账是一个典型例子。要从A用户账户转移200到B用户账户上,需要:

1.检查A用户账户余额高于200

2.从A用户账户余额中减去200

3.给B用户账户余额增加200

这三个步骤必须打包到一起,任何一个步骤失败,必须回滚所有步骤。

  • 启动事务
start transaction
select balance from checking where customer_id='A';
update checking set balance = balance-200 where customer_id = 'A';
update checking set balance = balance+200 where customer_id = 'B';
commit;

事务的标准特征

单纯的事务概念不足以说明一切。如果在第三和第四条语句之间,令一个进程要删除A的余额,那么服务器不知道这个情况可能白给B用户200

所以一个良好的事务处理系统,必须具备这些标准特征(ACID)

  • 原子性 Atomicity
一个事务必须看做一个不可再分的基本单位,要么全部成功,要不失败回滚。
不可能只操作其中一部分操作。
  • 一致性 Consistency
数据库总是从一个一致性状态转换到另一个一致性状态
  • 隔离性 Isolation
一般来说,一个事务所做的修改在未提交时,对其他事务是不可见的。
根据情况又有不同的隔离级别。
  • 持久性 Durability
一旦事务提交,其所做的修改就会永久保存到数据库内。

事务的ACID特性保证了银行不会弄丢你的钱,或者其他情况。但实际上要实现却比较麻烦,事务处理过程中额外的安全性,需要数据库系统做更多的额外工作,需要有更强的CPU处理能力,要更大的内存和磁盘空间。

隔离级别

隔离性比较复杂。SQL中标准定义了四种隔离级别,每一种隔离级别都规定了一个事务的修改和事务间那些是可见的,那些不可见。低级别的隔离可执行更高的并发,系统开销也低。

  • Read Uncommitted 未提交读
事务的修改,就算没有提交,其他事务也是可见的。
事务读取到其他事务未提交的数据,叫做脏读。

这个级别 会导致很多问题,效率也高不了太多,因此很少用到
  • Read Committed 提交读
满足事务开始时,只能“看见”已经提交的事务做的修改。
但是,同样因此一个事务所做的修改,在提交前,其他事务都不可见。

因此,执行两次同样的查询,可能得到不一样的结果。也就是不可重复读
这个隔离级别解决了脏读,但没有解决不可重复读的问题
  • Repeatable Read 可重复读(mysql默认级别)
该级别解决了脏读,而且保证同一个事务多次读取的结果是一致的
但是无法解决幻读问题

幻读问题是指事务读取某个范围的记录时,有其他事务在该范围内插入了记录。
当前事务再次读取该范围时出现了幻行
InnoDB通过MVCC(多版本并发控制)解决幻读问题
  • Serializable 可串行化
是最高的隔离级别,通过强制事务串行执行,解决了之前的问题。

加锁,可能导致大量超时和锁争用问题。实际很少用到

mysql不可重复读 可重复读_版本号

MySQL中事务

MySQL中提供两种事务型引擎:InnoDB和NDB Cluster。另外其他三方存储引擎也支持事务,有XtraDB和PBXT

  • 自动提交
    MySQL使用自动提交,也就是不显示地开始一个事务,则每个查询都和被当作事务执行操作。
    InnoDB也支持所有的隔离级别
  • 混用存储引擎
    MySQL服务器不管理事务,事务是由下层的存储引擎实现的,因此同一个事务中,使用多种存储引擎是不可靠的。
    如果混用了事务型和非事务型引擎,正常情况不会有什么问题。但事务需要回滚时,非事务型的表变更就无法撤销。这种就很难修复。

多版本并发控制

一般来说,MySQL事务型存储引擎实现都不是简单的行级锁。一般都是实现了多版本并发控制(MVCC)

我们可以认为MVCC是行级锁的一个变种,但很多情况避免了加锁操作,因此开销更低。

  • 快照
    MVCC的实现,是通过保存数据在某个时间点的快照来实现的。
快照就是不加锁时select读取的结果。也就是不加锁的非阻塞读取。
如果是串行情况下,快照读就会变成当前读。

MVCC就是使用了快照读
不管需要执行多长时间,每个事务看到的数据是一致的。

但是,根据事务的开始时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。
  • 类型
    乐观并发控制 悲观并发控制
  • 实现
    InnoDB的MVCC是通过每行记录后面两个隐藏的列来实现的。
1.保存行的创建时间

2.保存行的过期时间(或删除时间)

存储的是系统版本号。
每开始一个事务,系统版本号都会自动递增。事务开始的系统版本号作为事务的版本号。
用事务的版本号和查询的每行记录的版本号进行比较。

select:

查找版本早于当前事务版本的数据行。这样保证数据要么是事务开始前存在,要么是事务自身插入或修改的。

行的删除版本要么未定义,要么大于事务版本号,保证事务读取时,还没有删除。

insert:

为插入的每一行保存当前系统版本号作为行版本号

delete:

为删除的每一行保存当前系统版本号为行删除标识

update:

插入一条新数据,保存当前系统版本号作为行版本号,并且保存当前系统版本号到原来的行作为行删除标识。

保存这两个系统版本号,使大多数读不需要加锁,使数据库操作简单,性能很好,并且只会读取到符合标准的行。不足就是需要额外的存储空间。

MVCC只在Repeatable Read和Read committed两个隔离级别下工作,其他两个隔离级别和MVCC不兼容。



mysql不可重复读 可重复读_MySQL_02