MySQL 事务

发布于:2024-07-27 ⋅ 阅读:(30) ⋅ 点赞:(0)

引言

事务是数据库区别于文件系统的重要特性之一。数据库系统引入事务的主要目的:事务会把数据库从一种一致状态转换为另一种一致状态。 在数据库提交工作时,可以确保其要么所有修改都已经保存了,要么所有修改都不保存。

InnoDB存储引擎中的事务完全符合ACID的特性。

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

事务概述

事务是数据库区别于文件系统的重要特性之一。事务用来保证数据库的完整性——要么都做修改,要么都不做。同时,事务有严格的定义,必须同时满足四个特性。

  • 原子性:原子性指数据库事务是不可分割的工作单位。只有使事务中所有的数据库操作执行都成功,才算整个事务成功。如果事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句必须撤销。数据库状态应该退回到执行事务前的状态。
  • 一致性:一致性指事务将数据库从一种状态转变为下一种一致的状态。在事务开始之前和结束以后,数据库的完整性约束没有被破坏。
  • 隔离性:一个事务的影响在该事务提交前对其他事务不可见。
  • 持久性:事务一旦提交,结果是永久性的。

事务的实现

隔离性由锁来实现,原子性、一致性、持久性通过数据库的redo和undo来完成。

redo

在InnoDB存储引擎中,事务日志通过重做日志文件和InnoDB存储引擎的日志缓冲来实现。当开始一个事务时,会记录该事务的一个LSN(Log Sequence Number,日志序列号);当事务执行时,会向InnoDB存储引擎的日志缓冲里插入事务日志;当事务提交时,必须将InnoDB存储引擎的日志缓冲写入磁盘(默认的实现,即innodb_flush_log_at_trx_commit =1)。也就是 在写数据前,需要先写日志。这种方式称为预写日志方式(WAL)

InnoDB存储引擎通过预写日志的方式来保证事务的完整性。意味着在磁盘上存储的数据页和内存缓冲池中的页是不同步的。

undo

重做日志记录了事务的行为,可以很好的通过其进行“重做”,但是事务有时还需要撤销,这时就需要undo。undo和redo正好相反,对于数据库进行修改时,数据库不但会产生redo。还会产生一定量的undo,假如执行的事务或者语句由于某种原因失败了,或者使用一条rollback语句进行回滚。就可以利用undo信息将数据回滚到修改前的样子。

与redo不同的是,redo存放在重做日志文件中,undo存放在数据库内部的一个特殊段中,称为undo段,undo段位于共享表空间内。

undo操作是将数据库逻辑的恢复到原来的样子,所有修改被逻辑的取消。在多用户并发系统中,可能会有数十、数百甚至数千个并发事务。数据库的主要任务是协调对于数据记录的并发访问。如一个事务在修改当前一个页中某几条记录,但同时还有别的事务在对同一个页中另几条记录进行修改。因此,不能将一个页回滚到事务开始的样子,因为这样会影响其他事务正常进行工作。

补充,InnoDB的binlog、redo log、undo log
InnoDB存储引擎使用几种不同的日志来确保事务的ACID特性以及数据恢复能力。
1. redo Log(重做日志)

  • 作用:重做日志主要负责记录事务对数据库所做的修改操作。他的目的是在系统崩溃时能够恢复到最新的状态。当一个事务提交时,相关的更改首先记录到redo log中,这样即使在数据还未写入到磁盘上的数据文件之前系统发生故障,也能从redo log中重做这些操作,保证事务的持久性。
  • 写入时机: 在事务执行过程中,更改数据前先写入redo log缓存,然后随着事务的进行逐步刷新到磁盘上的redo log文件。

2. Undo Log(回滚日志)

  • 作用:回滚事务用于实现事务的原子性和一致性,他记录了事务对数据库所做的修改的反向操作。如果事务需要回滚或者在事务隔离级别下解决并发问题,undo log可以用来撤销已经执行的操作,恢复到事务开始前的状态。
  • 写入时机:在事务开始修改之前,会先写入undo log,这样在事务失败需要回滚时,根据undo log内容撤销所有改动。

3. binlog

  • 作用:binlog是MySQL服务器层的日志,与存储引擎无关,主要用于数据的复制和恢复。他记录了对数据库执行的所有更改数据的SQL语句或者数据的逻辑变更。BinLog对于主从复制至关重要,因为她允许从服务器根据主服务器执行的更改来更新自己的数据。
  • 写入时机:binlog是在事务提交之后写入的,意味着事务所有的更改都已经成功提交到数据库后,才会记录到binlog中,这和redo log的写入时机有所不同。

事务控制语句

  • start transaction | begin : 显示的开启一个事务

  • commit:提交事务,并使得已对数据库做的修改成为永久性的。

  • rollback:回滚事务,撤销正在进行的所有未提交的修改。

  • savepoint identifier: 在事务中创建一个保存点,一个事务中可以有多个savepoint。

  • release savepoint identifier : 删除一个事务的保存点,当没有一个保存点执行这句语句时,会抛出一个异常。

  • rollback to [savepoint] identifier : 这个语句和savepoint命令一起使用。可以把事务回滚到标记点,而不回滚此标记点之前的任何工作。例如可以发出两条update语句,后面跟一个savepoint,然后又是两条delete语句,如果执行delete语句期间出现了某种异常情况,而且捕获到了这个异常,可以发出rollback to savepoint命令,事务就会回滚到指定的savepoint,撤销delete完成的所有工作。rollback to savepoint命令并不真正的结束事务,需要显示的执行commit或者rollback命令才能结束一个事务。

  • set transaction: 这个语句用来设置事务的隔离级别。InnoDB存储引擎提供的事务隔离级别有:read uncommitted、read committed、repeatable read、serializable。

start transaction、begin语句都可以在mysql命令行下显示的开启一个事务。但是在存储过程中,mysql分析会自动将begin识别为begin…end。因此在存储过程中,只能使用start transaction语句来开启一个事务。

commit和commit work语句基本上是一致的,都用来提交事务。不同之处在于,commit work用来控制事务结束后的行为,是chain还是release。可以通过参数completion_type来进行控制,默认参数为0,表示没有任何操作。在这种设置下,commit和commit work是完全等价的。当参数completion_type为1时,commit work等价于commit and chain,表示马上自动开启一个相同隔离级别的事务。completion_type为2时,commit work 等同于commit and release 表示事务提交后自动断开和服务器的连接。

InnoDB存储引擎中的事务都是原子的,这说明下述两种情况:或者构成事务的每条语句都会提交(成为永久),或者所有语句都会回滚。

事务的隔离级别

SQL标准定义的四个隔离级别为

  • read uncommitted
  • read committed
  • repeatable read
  • serializable。

InnoDB存储引擎默认的支持隔离级别是repeatable read ,但是与标准SQL不同的是,InnoDB存储引擎在repeatable read事务隔离级别下,使用Next-Key Lock锁的算法,因此避免幻读的产生。因此,InnoDB存储引擎在默认隔离级别下已经能完全保证事务的隔离性要求,即达到SQL标准的serializable隔离级别。

隔离级别越低,事务请求的锁越少,或者保持锁的时间越短。在InnoDB存储引擎中,可以使用如下命令设置当前会话或者全局的事务隔离级别
set [global|session] transaction isolation level [read uncommitted| read committed|repeatable read | serializable]

如果想在MySQL库启动时就设置事务的默认隔离级别,需要修改MySQL配置文件如下

[mysqld]
transaction-isolation = read-committed

在serializable的事务隔离级别,InnoDB存储引擎会对每个select语句后自动加上lock in share mode,即给每个读取操作加一个共享锁。因此在这个事务隔离级别下,读占用锁了,一致性的非锁定读不在予以支持。serializable的事务隔离级别主要用于InnoDB存储引擎的分布式事务。

在read committed的事务隔离级别下,除了唯一性的约束检查以及外键约束检查需要Gap Lock,InnoDB存储引擎不会使用Gap Lock的锁算法。

分布式事务

InnoDB存储引擎支持XA事务,通过XA事务可以支持分布式事务的实现。分布式事务指的是允许多个独立的事务资源参与一个全局的事务中。事务资源通常是关系型数据库系统,全局事务要求在其中所有参与的事务要么都提交,要么都回滚。另外,在使用分布式事务时,InnoDB存储引擎事务隔离级别必须设置为serializable。

分布式事务可能在银行的转账系统中比较常见,如一个用户需要从上海转10000元到北京的一个用户上。
在这里插入图片描述
这种情况一定要使用分布式事务,如果不能都提交或者都回滚,在任何一个节点出现问题都会导致严重的结果。

分布式事务由一个或者多个资源管理器、一个事务管理器、一个应用程序组成。

  • 资源管理器:提供访问事务资源的方法。通常一个数据库就是一个资源管理器。
  • 事务管理器:协调参与全局事务中的每个事务,需要和参与全局事务中的所有资源管理器进行通信。
  • 应用程序:定义事务的边界,指定全局事务中的操作。

在MySQL分布式事务中,资源管理器就是MySQL数据库,事务管理器为连接到MySQL服务器的客户端。

在这里插入图片描述
分布式事务采用两阶段提交的方式,在 第一个阶段,所有参与全局事务的节点都开始准备,告诉事务管理器他们准备好提交了,在第二个阶段,事务管理器告诉资源管理器执行rollback还是commit。如果任何一个节点显示不能提交,则所有节点被告知需要回滚。


网站公告

今日签到

点亮在社区的每一天
去签到