MySQL事务详解

事务的使用流程

事务:一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务,一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成。
SQL 使用下列语句来管理事务。

(1)开始事务
BEGIN;START TRANSACTION;这个语句显式地标记一个事务的起始点。

(2) 提交事务
MySQL 使用COMMIT;语句来提交事务,即提交事务的所有操作,具体地说,就是将事务中所有对数据库的更新都写到磁盘上的物理数据库中,事务正常结束。

提交事务,意味着将事务开始以来所执行的所有数据都修改成为数据库的永久部分,因此也标志着一个事务的结束。一旦执行了该命令,将不能回滚事务。只有在所有修改都准备好提交给数据库时,才执行这一操作。

(3)回滚(撤销)事务
MySQL 使用ROLLBACK;语句回滚事务,即在事务运行的过程中发生了某种故障,事务不能继续执行,系统将事务中对数据库的所有已完成的操作全部撤销,回滚到事务开始时的状态。这里的操作指对数据库的更新操作。

当事务执行过程中遇到错误时,使用 ROLLBACK 语句使事务回滚到起点或指定的保持点处。同时,系统将清除自事务起点或到某个保存点所做的所有的数据修改,并且释放由事务控制的资源。因此,这条语句也标志着事务的结束。

ACID四大特性

ACID四大特性之中,C(一致性)是目的,A(原子性)、I(隔离性)、D(持久性)是为了保证一致性,数据库提供的手段。数据库必须要实现AID三大特性,才有可能实现一致性。

一致性

一致性:执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的。

Mysql通过如下两个层面保证一致性的:

  1. 从数据库层面,数据库通过原子性、隔离性、持久性来保证一致性。也就是说ACID四大特性之中,C(一致性)是目的,A(原子性)、I(隔离性)、D(持久性)是手段,是为了保证一致性,数据库提供的手段。数据库必须要实现AID三大特性,才有可能实现一致性。
  2. 从应用层面,通过代码判断数据库数据是否有效,然后决定回滚还是提交数据。

原子性

原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用。

MySQL原子性的实现依赖于Innodb的undo log ,undo log名为回滚日志,是实现原子性的关键。undo log记录了这些回滚需要的信息,比如一条INSERT语句,对应一条DELETE的undo log,对于每个UPDATE语句,对应一条相反的UPDATE的undo log。当事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。

隔离性

隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的。

Mysql保证隔离性利用的是锁和MVCC机制

MVCC,即多版本并发控制(Multi Version Concurrency Control),一个行记录的数据有多个版本的快照数据,这些快照数据在undo log中。如果一个事务读取的行正在做DELELE或者UPDATE操作,读取操作不会等行上的锁释放,而是读取该行的快照版本。快照度和当前读的解释如下:

  1. 快照读:读取的是快照版本,也就是历史版本。
  2. 当前读:读取的是最新版本。

普通的SELECT就是快照读,而UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE是当前读。

在InnoDB中,给每行增加两个隐藏字段来实现MVCC,一个用来记录数据行的创建时间,另一个用来记录行的过期时间(删除时间)。在实际操作中,存储的并不是时间,而是事务的版本号,每开启一个新事务,事务的版本号就会递增。

于是乎,默认的隔离级别(REPEATABLE READ)下,增删查改变成了这样:

  1. SELECT:读取创建版本小于或等于当前事务版本号,并且删除版本为空或大于当前事务版本号的记录。这样可以保证在读取之前记录是存在的。
  2. INSERT:将当前事务的版本号保存至行的创建版本号。
  3. UPDATE:新插入一行,并以当前事务的版本号作为新行的创建版本号,同时将原记录行的删除版本号设置为当前事务版本号。
  4. DELETE:将当前事务的版本号保存至行的删除版本号。

持久性

持久性:一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

MySQL持久性的实现依赖于Innodb的redo log。Mysql是先把磁盘上的数据加载到内存中,在内存中对数据进行修改,再刷回磁盘上。当做数据修改的时候,不仅在内存中操作,还会在redo log中记录这次操作。当事务提交的时候,会将redo log日志进行刷盘(redo log一部分在内存中,一部分在磁盘上)。当数据库宕机重启的时候,会将redo log中的内容恢复到数据库中,再根据undo log和binlog内容决定回滚数据还是提交数据。

redo log 的刷盘策略:redo log的写入并不是直接写入磁盘的,InnoDB引擎会在写redo log的时候先写redo log buffer,之后以一定的频率刷入到真正的redo log file 中,它支持三种策略:

  1. 设置为0 :表示每次事务提交时都不进行刷盘操作,而是每隔1s进行一次刷盘操作。
  2. 设置为1 :表示每次事务提交时都进行刷盘操作( 默认值 )。
  3. 设置为2 :表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由操作系统自己决定什么时候刷盘。

三个日志

  1. 重做日志(redo log):确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。需要注意redo log的刷盘策略。

  2. 回滚日志(undo log):保存了事务发生之前的数据的一个版本,可以用于回滚(实现原子性),同时可以提供多版本并发控制下的读(MVCC)。回滚的实现方式大致如下:insert: 插入一条记录时,将这条记录的主键记录下来,回滚时根据这个主键删除即可

  3. 二进制日志(bin log):用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步,用于数据库的基于时间点的还原。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值