一、什么是事务
事务一般是指要做的或所做的事情,在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元。
比如在现实生活中,经常进行转账操作,分为两个步骤:转入与转出,只有当两部分都完成才认为转账成功。如果其中任意操作异常没有执行成功,则会导致两账户的金额不同步,造成错误,为了避免上述错误,数据库引入事务。
二、事务执行流程
①查询操作先从Buffer Pool中查询数据,若存在则直接输出,不存在则读取磁盘中的数据并放入Buffer Pool。
②在操作任何数据之前,会先将数据的旧值写入undo log日志文件中,以便执行事务过程中出现异常后好回滚到事务执行之前的数据。
③然后再操作Buffer Pool(内存)中的数据并设置成脏页,同时将操作的数据写入到Redo Log Buffer。
④将Redo Log Buffer中的数据写入到os cache系统内核缓存中。
⑤系统内核调用fsync()将os buffer中的数据写入到redolog文件中,并设置状态为prepare。
⑥redolog文件写入完成后,由server层将执行的操作性修改,包括数据库结构和表数据的变更,但不包括select语句,写入到binlog文件中。
⑦binlog写入成功后,设置状态为commit。
⑧最后完成事务提交。
脏页什么时候会被刷入磁盘
一般来说,当事务提交后,MySQL首先更新的是 Buffer Pool 中数据所在的页,然后将该页设置为脏页,但是磁盘中还是原数据。因此,脏页需要被刷入磁盘,以保证缓存和磁盘数据一致,但是若每次修改数据都刷入磁盘,则性能会很差,因此一般都会在一定时机进行批量刷盘。数据刷盘的时机有以下几种:
①当 redo log 日志满了的情况下,会主动触发脏页刷新到磁盘。
②Buffer Pool 空间不足时,会先将脏页刷新到磁盘。
③MySQL 认为空闲时,后台线程回定期将适量的脏页刷入到磁盘。
④MySQL 正常关闭之前,会把所有的脏页刷入到磁盘。
三、事务特性
事务4 个特性:原子性、一致性、隔离性、持久性。
①原子性(atomicity)
原子性是指事务中的所有操作要么全部成功,要么全部失败,不会出现部分成功部分失败的情况。如果事务在执行过程中发生了错误,那么事务会回滚(rollback),即撤销已经执行的操作,恢复到事务开始之前的状态。MySQL通过使用回滚日志(undo log)来实现原子性,回滚日志记录了事务中对数据的修改,如果事务失败,就可以根据回滚日志恢复数据。
②一致性(consistency)
一致性是指事务在执行前后必须保持数据的一致性,即不会破坏数据的完整性和业务逻辑。例如,在转账事务中,转出账户和转入账户的总金额应该保持不变。MySQL通过使用锁(lock)来实现一致性,锁可以防止多个事务同时修改同一条数据,造成数据冲突或丢失。
③隔离性(isolation)
隔离性是指多个事务之间相互隔离,不会互相影响。例如,在转账事务中,转出账户的余额应该只受到本事务的影响,而不受到其他事务的影响。MySQL通过使用隔离级别(isolation level)来实现隔离性,隔离级别定义了一个事务在读取数据时能够看到其他事务对数据所做的修改的程度。MySQL支持四种隔离级别,分别是未提交读(read uncommitted)、已提交读(read committed)、可重复读(repeatable read)和可串行化(serializable),它们从低到高提供了不同程度的隔离性和并发性。
④持久性(durability)
持久性是指事务一旦提交(commit),那么对数据所做的修改就会永久保存在数据库中,即使发生系统崩溃或断电等异常情况,也不会丢失数据。MySQL通过使用重做日志(redo log)来实现持久性,重做日志记录了事务对数据所做的修改,如果系统崩溃或断电,就可以根据重做日志恢复数据。
四、事务隔离级别
①事务隔离级别重置
MySQL InnoDB存储引擎默认的事务隔离级别是可重复读(REPEATABLE READ)
MySQL 5.7 SELECT @@tx_isolation;
MySQL 8.0 SELECT @@transaction_isolation;
-- 设置当前会话 或者 全局隔离级别语法
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL
{READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
②事务隔离级别介绍
以下面表为例简单介绍MySQL各个事务隔离级别执行情况
CREATE TABLE `test1` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`name` varchar(20) NOT NULL DEFAULT '' COMMENT '姓名',
`age` tinyint NOT NULL DEFAULT '0' COMMENT '年龄',
`card_no` varchar(30) NOT NULL COMMENT '身份证号',
`base_info` text COMMENT '基础信息',
PRIMARY KEY (`id`),
UNIQUE KEY `test1_card_no_IDX` (`card_no`) USING BTREE,
KEY `test1_age_IDX` (`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COMMENT='测试1';
- 读未提交 (READ UNCOMMITTED)
最低级别,允许一个事务读取另一个事务尚未提交的数据。这可能导致脏读、不可重复读和幻读的问题。
事务A |
事务B |
begin; |
begin; |
update test1 set name='特朗普是懂王' where id=1; |
|
commit; |
|
update test1 set name=’拜登走路要摔倒’where id=1; |
|