目录
5.4、REPEATABLE READ 可重复读——InnoDB 默认的隔离级别
1、事务的4个特性ACID
原子性(Automicity):一个事务包含多个操作,这些操作要么全被成功执行,要么全都不被执行。
一致性(Consistency):一致性是针对数据的,不管事务执行成功与否,都不会破坏数据的完整性和一致性。
隔离性(Isolation):多个事务之间相互不影响。
持久性(Durability):事务一旦执行成功,那么事务的执行结果会存储于磁盘中,即便是计算机宕机或者重启,事务的结果仍然存在。
2、事务的分类
2.1、扁平事务
是我们最常用的一种事务,一般就是: BEGIN 开始,事务SQL,COMMIT 提交。扁平事务就是这些事务SQL 要么都被执行成功,要么都不被执行,所以 SQL 语句一视同仁。
2.2、具有保存点的扁平事务
扁平事务如果要回滚的话,所有的事务SQL的执行结果都要放弃(一棒子全打死),回归到事务执行前的状态,万一我觉得有一个部分事务SQL执行的挺好,没什么问题,只是因为极少数事务SQL 出了问题,你就要全部给我回滚,又要重头到尾来一遍,岂不是不划算。因此,具有保存点的扁平事务可以解决这个问题,它可以在事务SQL中设置多个保存点,这些保存点的序号是自增的,比如0,1,2,3,效果和自增主键是一模一样,当需要回滚时,可以指定回滚到哪个保存点,这样,该保存点之前的工作都被保留了,抛弃的只是保存点之后,ROLLBACK 之前的工作,如果此时ROLLBACK后面还有事务SQL没有执行完的话,会接着该保存点继续执行,直到COMMIT。
2.3、链事务
链事务就像链表一样,事务作为节点,一个事务连接着另一个事务,形成一条链表一样,当前面一个事务执行完成后,会以原子性地接着执行后一个事务(上一个事务的提交操作和下一个事务的开始是在一个原子操作内)。要回滚的话,也只是回滚当前事务节点,不会影响之前的事务。
链事务就好像是将一个大的工作拆成多个小的事务,这些小事务有顺序的,每一个小事务执行之后,开始下一个小事务,已经提交的小事务就没法回滚了,只能回滚当前的小事务。类似小时工,每过一个小时,你就要结工资,一旦钱拿到我手里了,就不会再吐出来了,只能说,你在当前一个小时还没结束的时候,还没有结工资,你可以说我做的不好,返工。
而保存点的扁平事务就像天工,每天结束的时候,才结工资(事务到最后提交一次,链事务是多次提交),反正一天长着呢,我随时可以让你返工,除非你最后提交了(结工资),我就没法了。
2.4、嵌套事务
在BEGIN COMMIT 之间还可以有多层 BEGIN COMMIT,这样就称为嵌套事务,就像一颗树结构,根事务(根节点),子事务(非叶子节点),叶子事务,叶子事务必须是扁平事务,其它的随意。一个子事务提交,不会真的完成提交,而是要等到其父事务完成提交,所以,要想整个事务树的执行结果都提交成功,就必须要等到根事务提交成功。反过来说,一个父事务的提交成功会导致它下面所有的子孙事务都提交成功。
2.5、分布式事务
在分布式系统下,可能一个事务的操作涉及多个节点,比如在A节点上做一点事,在B节点上做一点事,要保证这两部分事是一个事务,这就是分布式事务。
3、事务的4个工作原理
redo 日志。 redo 日志用于在保证事务的原子性 和 持久性,因为已经把整个事务的执行结果缓存了起来,保证所有操作都能得到结果,并且 redo 缓存刷新到 redo 日志文件中,起到了持久性的作用。
undo 日志。undo 日志保证事务的一致性,比如事务的部分SQL 已经执行了,产生了结果,但是由于后面的SQL 出了问题,必须要回滚,此时 undo 日志就用于恢复,比如 事务已经插入了一条数据, 数据库根据 undo 日志就可以删除该条数据。
purge 线程。对于 修改 和 删除操作,并不是立即修改数据库里的数据 或者 删除掉,而是逻辑上的修改和删除了,实际还没有删除 和 修改, 等目标数据上没有任何事务的时候, purge 线程去实际地修改 或者 删除 目标数据。
group commit。这是在提交事务时触发的 redo 日志刷新时,不仅仅刷新这个事务的redo日志,但凡是redo缓冲区中已经缓存好了的其它事务的redo日志,一并刷新了。
4、事务SQL
1、START TRANSACTION 或者 BEGIN: 表示开始一个事务。在一个存储过程中,开启事务只能用 START TRANSACTION。
2、COMMIT 或者 COMMIT WORK:表示提交事务。看看下面的全局参数,默认为NO_CHAIN = 0, 表示COMMIT 和 COMMIT WORK 没区别, 如果为 1,COMMIT 为提交事务, COMMIT WORK 表示提交当前事务后,立即开启一个链事务,即后面SQL语句为一个链事务的SQL,直到用回滚或者提交来表示结束。如果为 2,COMMIT WORK 表示提交完事务后,立即与数据库断开连接。
3、ROLLBACK 或者 ROLLBACK WORK:表示回滚事务。
4、SAVEPOINT 保存点名:表示在当前位置设置一个保存点。
5、RELEASE SAVEPOINT 保存点名: 删除一个保存点。
6、ROLLBACK TO SAVEPOINT 保存点名:回滚到指定保存点。
7、SET TRANSACTION ISOLATION LEVEL 事务隔离级别名:设置事务隔离级别。
4.1、事务数量统计
统计数据库一共处理了多少个事务的方法是。老版本中,com_commit 和 com_rollback 参数用于表示被成功提交的事务数量,被成功回滚的事务数量,但是新版本淘汰了这两个参数,因为只有显示地用 SQL 去 COMMIT 或者 ROLLBACK,这两个参数才会统计,对于隐式地事务提交 和 回滚,它们是不会统计的。因此,没什么意义呀,不管是显式的事务,还是隐式的事务,都是数据库开销呀,你光统计个显式的事务,并不能在数据库层面上去分析出什么内容,得出什么结论。但是新版本为了兼容老版本,还是保留了下来,现在如果你执行SQL : SHOW GLOBAL STATUS LIKE 'com_commit' ,会报错:
The 'INFORMATION_SCHEMA.GLOBAL_STATUS' feature is disabled; see the documentation for 'show_compatibility_56'
因为,com_commit 和 com_rollback 已经被禁用了, 全局参数 show_compatibility_56 就是禁用它们俩的参数,默认 OFF,表示禁用,不能查看了,如果你非要查看 com_commit 和 com_rollback 的值,要先设置 show_compatibility_56 = ON,才能查看。
新版本用于统计事务数量的是在 performance_schema 库下的global_status 表里的 Handler_commit ,Handler_rollback, 分别表示提交事务数量 ,回滚事务数量(都包含了显式,隐式的事务提交和回滚)。
若要统计一个时间段内的事务数量,就需要注意时间起点 和 截点,事务数量的变化。
5、事务隔离级别
5.1、赃读、幻读、不重复读
赃读是指,当一个事务A在提交之前,修改了数据,此时修改后的数据仅仅存在于缓存中,磁盘中还未更新,此时,另一个事务B来读取此数据,那么自然命中缓存,读取到的数据是缓存中的,但是就在事务B读取了之后,事务A执行出了问题,进行了回滚,数据的修改没有起作用,而事务B却拿到了一个脏数据。
幻读是指,在同一个事务A中,查询满足某条件的数据,但是由于其它事务又插入了一些满足该条件的数据,导致事务A再一次查询满足该条件的数据时,发现多了,这就是幻读。
不重复读是指,在同一事务A中,反复读取同一个数据,但是其他事务可能在此期间对数据进行了修改,导致在同一个事务A中,多次读取同一个数据,结果却是不一样的。
5.2、READ UNCOMMITTED 未提交读
这种隔离级别最低,但是性能最高,在这种隔离级别下,事务在读取数据的时候,不会加锁,因此性能开销最小,但是隔离效果不好,无法避免赃读,幻读,不重复读。 因为在事务读取期间,无法避免其它事务不回滚、不插入数据、不修改数据。
5.3、READ COMMITTED 提交读
这种隔离级别上升了一个等级,事务读取数据时,也不会对数据进行加锁,不过,它是看不见其它事务未提交的修改,因此,在这种隔离级别下,事务读取的数据一定是有效的数据,一定是其他事务提交成功的数据。因此,避免了赃读,但是不能避免幻读,不重复读,因为在事务读取期间,无法避免其它事务不插入数据,不修改数据。
5.4、REPEATABLE READ 可重复读——InnoDB 默认的隔离级别
这种隔离级别又上升了一个等级。事务读取数据时,也不会对数据进行加锁,不过,它是看不见其它事务未提交的修改,读取的数据一定是有效的数据,一定是其他事务提交成功的数据, 避免了赃读。随后会将第一次读取到的数据保存一份,只要在当前事务中,无论之后读取多少此该数据,都读取的是第一次的备份,所以在同一个事务中,多次读取同一个数据得到的结果是一样的,避免了不重复读。 总结,避免了赃读,不重复读,但是无法避免幻读。
5.5、SERIALIZABLE
最高级别的隔离。事务读取数据时,读取的数据一定是有效的数据,一定是其他事务提交成功的数据, 避免了赃读。并且会对要读取的数据进行加锁,只有等该事务读取完后,才允许其他事务修改数据或者添加数据,避免了幻读 和 不重复读。
-----------------------------如有不正确的,欢迎指出,谢谢。