目录
总结
什么是事务?
在MySQL数据库中,我们操作数据库的语句都是一条一条的,其中每一条语句都可以单独看成一个事务,也可以将多条语句看成一个整体充当一个事务;
然而有时候我们想要完成某种业务的时候(比如:银行转账),此时就需要多条语句,我们通常会将这些语句打包成一个操作整体,其中包含了一组数据库操作命令。事务会把其中所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么都执行,要么都不执行,(比如:转账的时候,要么转账成功,要么失败,总不能A的账户减了1000,但是B的账户没有增加)因此我们可以理解为事务是一个不可分割的工作逻辑单元(这有点像java中的原子操作的特点)。
总结: 事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态到另一种一致性状态)(什么是一致性,对于银行转账事务而言,一致性就是转账前A和B的账户总额为多少,转账后总额依旧是多少,后面会详细讲解)。事务也是逻辑上的一组操作,要么都执行,要么都不执行,(最经典的案例就是银行转账);
事务的四大特性:
事务具有 4 个特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),这 4 个特性通常简称为 ACID原则。
1. 原子性
事务是一个完整的操作。事务的各元素是不可分的(原子的)。事务中的所有元素必须作为一个整体去提交或者回滚。如果事务中的任何元素失败,则整个事务都将失败。
总结一句话:要么都完成,要么都不完成;
以银行转账事务为例,如果该事务提交了,则这两个账户的数据将会更新。如果由于某种原因,事务在成功更新这两个账户之前终止了,则不会更新这两个账户的余额,并且会撤销对任何账户余额的修改,事务不能部分提交。
2. 一致性
当事务完成时,数据必须处于一致状态。也就是说,在事务开始之前,数据库中存储的数据处于一致状态。在正在进行的事务中. 数据可能处于不一致的状态,如数据可能有部分被修改。然而,当事务成功完成时,数据必须再次回到已知的一致状态。通过事务对数据所做的修改不能损坏数据,或者说事务不能使数据存储处于不稳定的状态。
以银行转账事务事务为例。在事务开始之前,所有账户余额的总额处于一致状态。在事务进行的过程中,一个账户余额减少了,而另一个账户余额尚未修改,此时、两个账户余额的总额与未转账之前处于不一致状态。事务完成以后,两个账户余额的总额再次恢复到转账之前的一致状态。
3. 隔离性
对数据进行修改的所有并发事务是彼此隔离的,这表明事务必须是独立的,它不应以任何方式依赖于或影响其他事务。修改数据的事务可以在另一个使用相同数据的事务开始之前访问这些数据,或者在另一个使用相同数据的事务结束之后访问这些数据。
另外,当事务修改数据时,如果任何其他进程正在同时使用相同的数据,则直到该事务成功提交之后,对数据的修改才能生效。张三和李四之间的转账与王五和赵二之间的转账,永远是相互独立的。
4. 持久性
事务的持久性指不管系统是否发生了故障,事务处理的结果都是永久的。所以事务的持久性说的是结果的持久性;
一个事务成功完成之后,它对数据库所作的改变是永久性的,即使系统出现故障也是如此。也就是说,一旦事务被提交,事务对数据所做的任何变动都会被永久地保留在数据库中。
总结:
事务的 ACID 原则保证了一个事务或者成功提交,或者失败回滚,二者必居其一。因此,它对事务的修改具有可恢复性。即当事务失败时,它对数据的修改都会恢复到该事务执行前的状态
执行事务的语法和流程
MySQL 使用下列语句来管理事务。
1) 开始事务
START TRANSACTION ;
这个语句显式地标记一个事务的起始点。
2) 提交事务
MySQL 使用下面的语句来提交事务:
COMMIT ;
COMMIT 表示提交事务,即提交事务的所有操作,具体地说,就是将事务中所有对数据库的更新都写到磁盘上的物理数据库中,事务正常结束。
提交事务,意味着将事务开始以来所执行的所有数据都修改成为数据库的永久部分,因此也标志着一个事务的结束。一旦执行了该命令,将不能回滚事务。只有在所有修改都准备好提交给数据库时,才执行这一操作。
3) 回滚(撤销)事务
MySQL 使用以下语句回滚事务:
ROLLBACK ;
ROLLBACK 表示撤销事务,即在事务运行的过程中发生了某种故障,事务不能继续执行,系统将事务中对数据库的所有已完成的操作全部撤销,回滚到事务开始时的状态。这里的操作指对数据库的更新操作。
当事务执行过程中遇到错误时,使用 ROLLBACK 语句使事务回滚到起点或指定的保持点处。同时,系统将清除自事务起点或到某个保存点所做的所有的数据修改,并且释放由事务控制的资源。因此,这条语句也标志着事务的结束。
总结
在 START TRANSACTION 开启事务语句后面的 SQL 语句对数据库数据的更新操作都将记录在事务日志中,直至遇到 ROLLBACK 语句或 COMMIT 语句。如果事务中某一操作失败且执行了 ROLLBACK 语句,那么在开启事务语句之后所有更新的数据都能回滚到事务开始前的状态。如果事务中的所有操作都全部正确完成,并且使用了 COMMIT 语句向数据库提交更新数据,则此时的数据又处在新的一致状态。
并发事务引起的问题
多个事务并发运⾏,经常会操作相同的数据来完成各⾃的任务(多个⽤户对同⼀数据进⾏操作)会导致脏读、不可重复读、幻读问题;如下图:
脏读(Dirty read)
当⼀个事务正在访问数据并且对数据进⾏了修改,⽽这种修改还没有提交到数据库中,这时另外⼀个事务也访问了这个数据,然后使⽤了这个数据。因为这个数据是还没有提交的数据,那么另外⼀个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
不可重复读(Unrepeatableread)
指在⼀个事务内多次读同⼀数据。在这个事务还没有结束时,另⼀个事务也访问该数据。那么,在第⼀个事务中的两次读数据之间,由于第⼆个事务的修改导致第⼀个事务两次读取的数据可能不太⼀样。这就发⽣了在⼀个事务内两次读到的数据是不⼀样的情况,因此称为不可重复读。
幻读(Phantom read)
幻读与不可重复读类似。它发⽣在⼀个事务(T1)读取了⼏⾏数据,接着另⼀个并发事务(T2)插⼊了⼀些数据时。在随后的查询中,第⼀个事务(T1)就会发现多了⼀些原本不存在的记录,就好像发⽣了幻觉⼀样,所以称为幻读。
不可重复读和幻读对比
不可重复读的重点是修改⽐如多次读取⼀条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除⽐如多次读取⼀条记录发现记录增多或减少了。
事务的隔离级别
上面讲述了并发事务引起的脏读等问题,那么他们如何解决呢?就是通过事务的隔离级别来实现避免脏读、不可重复读、幻读等问题;
MySQL标准定义了四个隔离级别
- READ-UNCOMMITTED(读取未提交): 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- SERIALIZABLE(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
虽然 Serializable 隔离级别下的事务具有最高的安全性。但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用 Serializable 隔离级别。
-- 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
-- 设置事务隔离级别
SET[SESSION| GLOBAL] TRANSACTION ISOLATION LEVEL[ READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIAYABLE ]