【MySQL】事务的基本知识

199 阅读7分钟

事务基本知识

什么是事务

💡 一组逻辑操作单元,使数据从一种状态变换到另一种状态。

事务的ACID特性

💡
  • **原子性(atomicity):**原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
  • **一致性(consistency):**一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
  • **隔离型(isolation):**事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰。
  • **持久性(durability:**持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

事务的状态

💡
  • 活动的(active) :事务对应的数据库操作正在执行过程中时,我们就说该事务处在活动的 状态。
  • 部分提交的(partially committed) :当事务中的最后一个操作执行完成,但由于操作都在内存中执行,所造成的影响并 没有刷新到磁盘 时,我们就说该事务处在 部分提交的 状态。
  • 失败的(failed) :当事务处在 活动的 或者 部分提交的 状态时,可能遇到了某些错误(数据库自身的错误、操作系统 错误或者直接断电等)而无法继续执行,或者人为的停止当前事务的执行,我们就说该事务处在 失 败的 状态。
  • 中止的(aborted) :如果事务执行了一部分而变为 失败的 状态,那么就需要把已经修改的事务中的操作还原到事务执 行前的状态。换句话说,就是要撤销失败事务对当前数据库造成的影响。我们把这个撤销的过程称之为 回滚 。当 回滚 操作执行完毕时,也就是数据库恢复到了执行事务之前的状态,我们就说该事 务处在了中止的状态。
  • **提交的(committed):**当一个处在 部分提交的 状态的事务将修改过的数据都 同步到磁盘 上之后,我们就可以说该事务处在了 提交的 状态。

Untitled

如何开启事务

💡 显示事务 隐式事务

显示事务

BEGIN;
#或者
mysql> START TRANSACTION

START TRANSACTION 语句相较于 BEGIN 特别之处在于,后边能跟随几个修饰符 :

  • **READ ONLY** :标识当前事务是一个 只读事务 ,也就是属于该事务的数据库操作只能读取数据,而不能修改数据。

补充:只读事务中只是不允许修改那些其他事务也能访问到的表中的数据,对于临时表来说(我们使用 CREATE TMEPORARY TABLE 创建的表),由于它们只能再当前会话中可见,所有只读事务其实也是可以对临时表进行增、删、改操作的。

  • READ WRITE :标识当前事务是一个 读写事务 ,也就是属于该事务的数据库操作既可以读取数据, 也可以修改数据。
  • WITH CONSISTENT SNAPSHOT :启动一致性读。
START TRANSACTION READ ONLY; # 开启一个只读事务
START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT # 开启只读事务和一致性读
START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT # 开启读写事务和一致性读
  • READ ONLY和READ WRITE是用来设置所谓的事物访问模式的,就是以只读还是读写的方式来访问数据库中的数据,一个事务的访问模式不能同时即设置为只读的也设置为读写的,所以不能同时把READ ONLY和READ WRITE放到START TRANSACTION语句后边。
  • 如果我们不显式指定事务的访问模式,那么该事务的访问模式就是读写模式

隐式事务

  • 数据定义语言(Data definition language,缩写为:DDL) 数据库对象,指的就是数据库、表、视图、存储过程等结构。当我们CREATE、ALTER、DROP等语句去修改数据库对象时,就会隐式的提交前边语句所属于的事物。即: BEGIN;

    SELECT ... # 事务中的一条语句
    UPDATE ... # 事务中的一条语句
    ... # 事务中的其他语句
    
    CREATE TABLE ... # 此语句会隐式的提交前边语句所属于的事务
    
  • 隐式使用或修改mysql数据库中的表 当我们使用ALTER USER、CREATE USER、DROP USER、GRANT、RENAME USER、REVOKE、SET PASSWORD等语句时也会隐式的提交前边语句所属于的事务。

  • 事务控制或关于锁定的语句 ① 当我们在一个事务还没提交或者回滚时就又使用 START TRANSACTION 或者 BEGIN 语句开启了另一个事务时,会隐式的提交上一个事务。即: BEGIN;

    SELECT ... # 事务中的一条语句
    UPDATE ... # 事务中的一条语句
    ... # 事务中的其他语句
    
    BEGIN; # 此语句会隐式的提交前边语句所属于的事务
    

    ② 当前的 autocommit 系统变量的值为 OFF ,我们手动把它调为 ON 时,也会 隐式的提交前边语句所属的事务。 ③ 使用 LOCK TABLES 、 UNLOCK TABLES 等关于锁定的语句也会 隐式的提交 前边语句所属的事务。

  • 加载数据的语句 使用LOAD DATA语句来批量往数据库中导入数据时,也会隐式的提交前边语句所属的事务。

  • 关于MySQL复制的一些语句 使用START SLAVE、STOP SLAVE、RESET SLAVE、CHANGE MASTER TO等语句会隐式的提交前边语句所属的事务

  • 其他的一些语句 使用ANALYZE TABLE、CACHE INDEX、CAECK TABLE、FLUSH、LOAD INDEX INTO CACHE、OPTIMIZE TABLE、REPAIR TABLE、RESET等语句也会隐式的提交前边语句所属的事务。

数据的并发问题

💡
  • **脏写( Dirty Write ):**对于两个事务 Session A、Session B,如果事务Session A 修改了 另一个 未提交 事务Session B 修改过 的数据,那就意味着发生了 脏写
  • **脏读( Dirty Read ):**对于两个事务 Session A、Session B,Session A 读取 了已经被 Session B 更新 但还 没有被提交 的字段。 之后若 Session B 回滚 ,Session A **读取**的内容就是 临时且无效 的脏数据。
  • 不可重复读( Non-Repeatable Read ) :对于两个事务Session A、Session B,Session A **读取**了一个字段,然后 Session B **更新**了该字段。 之后 Session A 再次读取 同一个字段, 值就不同 了。那就意味着发生了不可重复读。
  • 幻读( Phantom ):对于两个事务Session A、Session B, Session A 从一个表中 读取 了一个字段, 然后 Session B 在该表中 插 入 了一些新的行。 之后, 如果 Session A 再次读取 同一个表, 就会多出几行。那就意味着发生了幻读

事务的隔离级别

💡
  • READ UNCOMMITTED :读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结 果。不能避免脏读、不可重复读、幻读
  • READ COMMITTED :读已提交,它满足了隔离的简单定义:一个事务只能看见已经提交事务所做 的改变。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。可以避免脏读,但不可重复读、幻读问题仍然存在。
  • REPEATABLE READ :可重复读,事务A在读到一条数据之后,此时事务B对该数据进行了修改并提 交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但幻读问题仍然存在。这是MySQL的默认隔离级别。
  • SERIALIZABLE :可串行化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止 其他事务对该表执行插入、更新和删除操作。所有的并发问题都可以避免,但性能十分低下。能避免脏读、不可重复读和幻读。

Mysql支持的隔离级别

💡 MySQL的默认隔离级别为`REPEATABLE READ`,Mysql在RR隔离级别下可以禁止幻读的发生。

事务的分类

💡 从事务理论的角度来看,可以把事务分为以下几种类型:
  • 扁平事务(Flat Transactions)
  • 带有保存点的扁平事务(Flat Transactions with Savepoints)
  • 链事务(Chained Transactions)
  • 嵌套事务(Nested Transactions)
  • 分布式事务(Distributed Transactions)