MySql 中的事务


事务

什么是事务
  1. a 事务(Transaction)是数据库区别于文件系统的重要特征之一,事务会把数据库从一种一致性状态转换为另一种一致性状态

  2. b 在数据库提交时,可以确保要么所有修改都已保存,要么所有修改都不保存

 

  • 简单来说就是干一系列事,要么最终完成,要么前面干的也都废了

  1. Mysql中关于事务的语句:

    1. BEGIN或START TRANSACTION;显式地开启一个事务;

      COMMIT;也可以使用COMMIT WORK,不过二者是等价的。COMMIT会提交事务,并使已对数据库进行的所有修改称为永久性的;

      ROLLBACK;有可以使用ROLLBACK WORK,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;

      SAVEPOINT identifier;SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT;

      RELEASE SAVEPOINT identifier;删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;

      ROLLBACK TO identifier;把事务回滚到标记点;

      SET TRANSACTION;用来设置事务的隔离级别。InnoDB存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ
  • 在 MySQL 中只有使用了 lnnodb 数据库引擎的数据库或表才支持事务

  • 在事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行

  • 事务用来管理 insert update delete 语句

 

MyLsam

 


事务的特性(ACID)
  • a 原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行

  • b 一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果一致

  • c 隔离性(lsolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的

  • 持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,机试数据库出现故障

 

 


 

事务的分类
扁平事务(Flat Transactions)
  • a 扁平事务是事务类型中最简单但使用最频繁的事务

  • 在扁平事务中,所有的操作都处于同一层次,由BEGIN/START TRANSACTION 开始事务,由COMMIT/ROLLBACK 结束,且都是原子的,要么都执行,要么都回滚

  • c 扁平事务是应用程序成为原子操作的基本组成模块

 

 

链事务
什么是链事务
  • a 链事务(Chained Transaction)是指一个事物由多个子事务链式组成

  • b 前一个子事务的提交操作和下一个子事务的开始操作合并成一个原子操作,这意味着下一个事务将看到上一个事物的结果,就好像在事务中进行的一样

  • c 在提交子事务时就可以释放不需要的数据对象,而不必等到整个事务完成后才释放

链事务工作示意图

 

 

链事务与扁平事务的区别:
  • a 链事务中的回滚仅限于当前事务,相当于只能恢复到最近的一个保存点

  • b 带保存节点的扁平事务能回滚到任意正确的保存点

  • c 带保存节点的扁平事务中的保存点事易失的,当发生系统崩溃时,所有的保存点都将消失,这意味着当进行恢复时,事务需要从开始处重新执行

 


 

嵌套事务
什么是嵌套事务
  • a 嵌套事务(Nested Transaction)是一个层次结构框架

  • b 有一个顶层事务(top-level transaction)控制各个层次的事务

  • c 顶层事务之下嵌套的事务成为子事务(subtransaction)其控制着每一个局部的操作,子事务本身也可以是前台事务

  • d 嵌套事务的层次结构可以看成是一棵树

嵌套事务结构如下图所示:

 

 


事务的隔离级别
SQL标准定义的四个隔离级别:
  • READ UNCOMMITTED:未提交读,作用域为(global)全局、(session)当前会话

 

 

读取未提交内容,在该隔离级别下,所有事务都可以看到其他未提交事务的执行结果

  1. a 事务2查询到的数据是事务1中修改但未提交的数据

  2. b 但因为事务1回滚了数据,所以事务2查询的数据是不正确的

  3. c 因此出现了脏读的问题

READ COMMITTED:提交读
  • 读取提交内容。在该隔离级别下,一个事务从开始到提交之前对数据所做的改变对其它事务是不可见的,这样就解决在READ-UNCOMMITTED级别下的脏读问题。

  • 但如果一个事务在执行过程中,其它事务的提交对该事物中的数据发生改变,那么该事务中的一个查询语句在两次执行过程中会返回不一样的结果

 

 

  1. 事务2执行uodate语句但未提交前,事务1的前两个select操作返回结果是相同的

  2. 但事务2执行commit 操作后,事务1的第三个select操作就读取到事务2对数据的改变,导致与前两次select操作返回不同的数据

  3. 因此出现了不可重复读的问题

REPEATABLE READ:可重复读
  • 可重复读。这是MySQL的默认事务隔离级别,能确保事务在并发读取数据时会看到同样的数据行,解决了READ-COMMITTED隔离级别下的不可重复读问题

  • MySQL的InnoDB存储引擎通过多版本并发控制(Multi_Version Concurrency Control, MVCC)机制来解决该问题

  • 在该机制下,事务每开启一个实例,都会分配一个版本号给它,如果读取的数据行正在被其它事务执行DELETE或UPDATE操作(即该行上有排他锁),这时该事物的读取操作不会等待行上的锁释放,而是根据版本号去读取行的快照数据(记录在undo log中)

  • 这样,事务中的查询操作返回的都是同一版本下的数据,解决了不可重复读问题

 

 

  1. 虽然该隔离级别下解决了不可重复读问题,但理论上会导致另一个问题:幻读(Phantom Read)

  2. 正如上面所讲,一个事务在执行过程中,另一个事物对已有数据行的更改

  3. MVCC机制可保障该事物读取到的原有数据行的内容相同,但并不能阻止另一个事务插入新的数据行,这就会导致该事物中凭空多出数据行,像出现了幻读一样,这便是幻读问题

 

 

  1. 事务2对id=1的行内容进行了修改并且执行了commit操作

  2. 事务1中的第二个select操作在MVCC机制的作用下返回的仍是v=1的数据

  3. 事务3执行了insert操作

  4. 事务1第三次执行select操作时便返回了id=2的数据行,与前两次的select操作返回的值不一样

需要说明的是,REPEATABLE-READ隔离级别下的幻读问题是SQL标准定义下理论上会导致的问题,MySQL的InnoDB存储引擎在该隔离级别下,采用了Next-Key Locking锁机制避免了幻读问题。Next-Key Locking锁机制将在后面的锁章节中讲到。

serializable:可串行读
  1. 可串行化。这是事务的最高隔离级别

  2. 通过强制事务排序,使之不可能相互冲突,就是在每个读的数据行加上共享锁来实现

  3. 在该隔离级别下,可以解决前面出现的脏读、不可重复读和幻读问题

  4. 但也会导致大量的超时和锁竞争现象,一般不推荐使用。


Django 中的事务

settings.py中关于事务的两个重要参数

ATOMIC_REQUESTS :全局控制所有的 request view是否是原子化, django默认每个request 不是原子化请求

AUTOCOMMIT : 全局控制事务是否自动提交

 

 

  1. 全局设置每个request当作一个原子化请求:

    ATOMIC_REQUESTS = True

  2. 如果全局设置所有的request当作一个事务,而又不想某一个view开启原子化事务,通过下面的设置:

 

 

  1. 如果ATOMIC_REQUEST 为False, 通过装饰器,明确控制每个request 为原子化事务:

 

 

  1. 代码块方式控制些语句操作为原子化操作

 

 


事务自动提交与手动提交:

在SQL标准中,每个SQL查询/或修改启动一个事务,除非存在一个活跃的事务则不需要开启新的事务,

SQL中必须显式地提交或回滚这些事务。

这对应用程序开发人员来说并不总是方便的。为了缓解这个问题,大多数数据库都提供了自动提交模式。

当自动提交被打开且没有事务处于活动状态时,每个SQL查询将被包装在它自己的事务中。换句话说,不仅每个这样的查询启动一个事务,而且事务还会自动提交或回滚,取决于查询是否成功。

django 默认全局是自动提交:

 

 

手动指定提交:

transaction.commit()

 

 

 

 

 

 

保存点与回滚到指定保存点

 

 

 

注意,必须是这种写法回滚才生效

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-09-18 08:32  宋小凯  阅读(304)  评论(0编辑  收藏  举报