一、MySQL事务
1、什么事事务
事务(transaction)就是一个最小的单独任务单元由一个或多个SQL语句组成,在这个任务单元中,每个SQL语句都是相互依赖,整个任务单元是作为一个不可分割的整体存在并执行。单元事务内的所有SQL要么都执行成功,要么都不执行。不可能存在部分执行成功而部分执行失败的情况。
例如:
你去银行转账10000元给你朋友,你的账户扣除10000,你朋友的账户增加10000这就是一个最小单元事务;在扣除你账号10000后因故障你朋友账号没有增加10000,银行不认账你是不是会哭了,或者事务SQL顺序是你朋友账号先增加10000时银行取款系统出现故障没有扣除你账号的10000元,事后你们两是不是会大吃一顿呢?
所以要么就是单元事务中的所有SQL语句都顺利执行成功,该事务也就被顺利执行完成。要么单元事务中某条SQL语句一旦执行失败或者产生错误,那么整个单元事务将会回滚(返回最初状态),所有受到影响的数据将返回到事务开始之前的状态。银行不欠你,你也不赚银行的10000元!
2、事务的四个特性(简称 ACID ):
原子性(Atomicity ):一个事务是一个不可再分割的整体,所有操作要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性(Consistency ):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
隔离性(Isolution ):一个事务不受其他事务的影响,并且多个事务彼此隔离,一个事务内部的操作及使用的数据,对并发的其他事务是隔离的,并发执行的各个事务之间不会互相干扰;事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)
持久性(Durability ):一个事务一旦被提交,在数据库中的改变就是永久的,提交后就不能再回滚,一个事务被提交后,在数据库中的改变就是永久的,即使系统崩溃重新启动数据库数据也不会发生改变
3、事务处理控制方式:
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务,事务由DML(insert、update、delete)语句共同联合完成,或者说DML语句才有事务(DDL语句create table/drop table/alter/table、lock tables语句等是自动立即提交执行不支持事务的);默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
直接用 SET 来改变 MySQL 的自动提交模式:
SET AUTOCOMMIT=0 禁止自动提交
SET AUTOCOMMIT=1 开启自动提交
用 BEGIN, ROLLBACK, COMMIT来实现
BEGIN 或 START TRANSACTION开始一个事务
ROLLBACK 事务回滚
COMMIT 事务确认
4、事务控制语句:
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 COMMITTED、REPEATABLE READ 和 SERIALIZABLE
5、事务的并发问题
在不同隔离级别下,数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题
具体举例说明如下:
现在有两个事务,分别是事务 A 和事务 B, 库存中有金条数量为1
脏读:
当前事务A中可以读到其他事务B未提交的数据(脏数据),这种现象是脏读。
例如事务B 售卖数量为1并修改这一条数据为0并未提交,事务 A 查询金条数据为0;事务B顾客撤销订单并回滚数据,这时候事务 A 读到就是脏数据
不可重复读:
不可重复读:在事务A中先后两次读取同一个数据,两次读取的结果不一样,这种现象称为不可重复读。脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。
例如事务 A 查询金条数据为1;事务B 中售卖数量为1并修改这一条数据为0并提交,这时候事务 A 再去查金条库存居然变为了0,事务A前后两次查询同一条数据不一致这就是不可重复读
幻读:
在事务A中按照某个条件先后两次查询数据库,两次查询结果的条数不同,这种现象称为幻读。不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了。
例如事务A 中售卖数量为1并修改这一条数据为0并提交查询库存已为0;这时候事务 B 中的库存管理员入库1条金条,库存变为1,事务A再去查询库存既然库存有,这就是幻读(幻读和不可重复读有点类似,区别就是幻读是新增加的一条数据)
6、两段锁协议
数据库在调度并发事务时遵循“两段锁”协议,“两段锁”协议是指所有事务必须分两个阶段对数据项进行加锁和解锁
扩展阶段:在对任何数据项的读、写之前,要申请并获得该数据项的封锁。收缩阶段:每个事务中,所有的封锁请求必须先于解锁请求。
在数学上可以证明,遵循两段锁的调度可以保证调度结果与串行化调度相同。这样的机制保证了数据库并发调度与串行调度的等价。
二、隔离级别
1、三级加锁协议
了解隔离级别之前需要先知道数据库的三级加锁协议也称为三级封锁协议,是为了保证正确的调度事务的并发操作,事务在对数据库对象加锁,解锁是必须遵守的一种规则.在运用X锁和S锁对数据对象加锁时,还需要约定一些规则 ,例如何时申请X锁或S锁、持锁时间、何时释放等。称这些规则为封锁协议(Locking Protocol)。对封锁方式规定不同的规则,就形成了各种不同的封锁协议。
封锁协议
三级协议的主要区别在于什么操作需要申请封锁,以及何时释放。
- 一级封锁协议
一级封锁协议是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。
一级封锁协议可以防止丢失修改,并保证事务T是可恢复的。使用一级封锁协议可以解决丢失修改问题。
在一级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,它不能保证可重复读和不读“脏”数据。 - 二级封锁协议
二级封锁协议是:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后方可释放S锁。
二级封锁协议除防止了丢失修改,还可以进一步防止读“脏”数据。但在二级封锁协议中,由于读完数据后即可释放S锁,所以它不能保证可重复读。 - 三级封锁协议
三级封锁协议是:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。
三级封锁协议除防止了丢失修改和不读“脏”数据外,还进一步防止了不可重复读。
2、事务隔离级别
三级封锁协议反映在实际的数据库系统上,就是四级事务隔离机制。总的来说,四种事务隔离机制就是在逐渐的限制事务的自由度,以满足对不同并发控制程度的要求。以下就是数据库的四种隔离级别:
Read Uncommitted(读未提交)、Read Committed(读提交)、Repeatable Read(可重复读)、Serializable(串行化)
其对各个并发问题的制约强度见下表:
√: 可能出现 ×: 不会出现
脏读 | 不可重复读 | 幻读 | |
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable read | × | × | √ |
Serializable | × | × | × |
四种级别对并发问题的解决由弱到强,相应的系统性能由强到弱,MySQL的默认级别是Repeatable Read。
- Read Uncommitted
在Read Uncommitted策略下,数据库遵循一级封锁协议,只对修改数据的并发操作做限制。一个事务不能修改其他事务正在修改的数据,但可以读取到其他事务中尚未提交的修改,这些修改如果未被提交,将会成为脏数据。 - Read committed
在Read committed策略下,数据库遵循二级封锁协议,只允许读取已经被提交的数据,反过来讲,如果一个事务修改了某行数据且尚未提交,而第二个事务要读取这行数据的话,那么是不允许的。在MySql的InnoDB下,虽然这种操作不被允许,但MySQL不会阻塞住数据的查询操作,而是会查询出数据被修改之前的备份,返回给客户端。MySQL的这种机制称为MVCC(多版本并发控制),就是说数据库在事务并发的过程中对数据维护多个版本,使得不同的事务对不同的数据版本进行读写(MVCC的实现参见引用中的文章)。这样的机制反映在应用中就是,在任何时候对数据库查询总是可以得到数据库中最近提交的数据。为被提交的脏数据被隔离起来,无法被查询到,即防止脏读发生。 - Repeatable read
Repeat Read又比Read Committed更加严格一点,但仍然是在二级封锁协议的范畴,只是读取过程受到更多MVCC的影响。在Read Committed下,允许一个事务中多次相同查询得到不同的结果,就是所谓的不可重复读问题。这在一些应用中是允许的,所以oracle、SQL server上默认这一隔离级别,但MySQL没有,它默认Repeat Read级别。在这一级别下,有赖于MVCC,同一个事务中的查询只能查到版本号不高于当前事务版本的数据,即事务只能看到该事务开始前或者被该事物影响的数据。反过来说,这一级别下,不允许事务读取在该事务开始后新提交的数据。即防止了不可重复读的发生。
依靠上面的机制,已经做到了在事务内数据内容的不变,但是不能保证多次查询得到的数据数量一致。因为在一个事务执行的过程中别的事务完全可以执行数据插入,当插入了刚好符合查询条件的数据时,就会引发数据查询结果集增加,引发幻读。还有一种情况就是,如果一个事务想插入一条数据,而另一个事务已经插入了含有相同主键的数据,那么当前事务也会被阻塞,并最终执行失败,虽然当前事务根本无法查询到这一条数据,这也是一种幻读。InnoDB提供的间隙锁机制可以在一定程度上防止幻读的发生,具体介绍见最后一篇引文。 - Serializable
最后,最强事务隔离机制Serializable,它遵循三级封锁协议,使得所有的事务必须串行化执行,只要有事务在对表进行查询,那么在此事务提交前,任何其他事务的修改都会被阻塞。这解决了一切并发问题,但会造成大量的等待、阻塞甚至死锁,使系统性能降低。
要注意,在任何一种隔离机制下,都是不允许一个事务删除或修改另一个事务影响过而未提交的数据的。因为事务增、删、改数据以后,会在该行加上排它锁,排它锁会阻塞其他事务再次对该行数据操作。也正是由于排它锁的存在,这四种隔离机制都不会出现任何一种更新丢失的现象,因为一条信息根本不允许第二个事务进行修改。
参考:
MySQL事务隔离性与隔离级别
https://blog.csdn.net/qq_37924905/article/details/117392821
MySQL 事务四大特性和事务隔离级别
https://blog.csdn.net/qq_40994734/article/details/125230201
mysql事务(详解)
https://blog.csdn.net/qq_45830276/article/details/125246751
mysql中的事务是什么
https://m.php.cn/article/488945.html
MySQL事务(transaction) (有这篇就足够了..)
https://blog.csdn.net/qq_56880706/article/details/122653735
MySQL之事务
https://baijiahao.baidu.com/s?id=1709428402761709469&wfr=spider&for=pc
MySQL 事务
https://www.runoob.com/mysql/mysql-transaction.html
理解MySql事务隔离机制、锁以及各种锁协议
https://www.2cto.com/database/201408/327940.html
http://blog.csdn.net/fg2006/article/details/6937413
http://blog.csdn.net/chen77716/article/details/6742128
http://www.2cto.com/database/201304/201415.html
http://snailxr.iteye.com/blog/1143615
http://blog.sina.com.cn/s/blog_711b11fd0101bhks.html
http://blog.sina.com.cn/s/blog_499740cb0100ugs7.html
标签:封锁,事务,隔离,--,笔记,Read,提交,mysql,数据 From: https://www.cnblogs.com/hsjz-xinyuan/p/16809201.html