当前位置: 首页 > article >正文

数据库事务

Innodb引擎支持以事务的方式执行SQL,事务包含ACID四个特性,分别是原子性、一致性、隔离性和持久化。

原子性

原子性是指开启事务后,使用commit提交事务或rollback回滚事务,使事务内的多条修改语句同时成功或失败。

原子性是通过redo log和undo log的方式实现。一起成功是通过在执行变更语句时,先把执行的sql先记录到redo log。记录成功后,代表变更结果已经持久化。一起都失败是事务开始后,对每条记录的变更都会记录undo log,在回滚事务的时候,通过undo log里记录的之前版本的数据进行回滚数据。

Redo Log为同个数据页下的多条数据变更记录一条日志

TransactionID: 127
PageID: 462
Operation: MULTIPLE_UPDATES
Updates:
  - UpdateType: UPDATE
    Before Image: (1, '小明')
    After Image: (1, '小李')
  - UpdateType: INSERT
    After Image: (2, '小红')
  - UpdateType: DELETE
    Before Image: (3, '小张')

Undo Log为每条变更的数据独立记录一条日志

TransactionID: 126
PageID: 459
Operation: UPDATE
Before Image: (1, '小明')

一致性

一致性是指事务结束后,各个表变更的记录状态是一样的。要么是成功状态,要么是失败状态,也就是开启事务之前的状态。在数据库发生意外奔溃时,会通过redo log和undo log恢复到崩溃之前的状态,确保数据库前后的一致性。

一致性是通过原子性、隔离性和持久性保证的。

隔离性

事务有不同的隔离级别,数据变更后,在不同事务之间,可见性不一样。

读未提交

是最弱的隔离级别,当前事务可以看见其他未提交事务的数据变更结果,这种现象称为脏读。

读已提交

当前事务可以看见其他已提交事务的数据变更结果。例如,第一次查询到的列a值等于1,第二次查到列a值等于2。这种现象称为不可重复读,也就是事务内没做修改,但是两次select查询到的结果不一样。

可重复读

当前事务无法看到其他事务的数据变更结果。也就是事务内没做修改,两次select查询到的结果基本是一样的。除了一种情况,第一次查询了范围数据,然后其他事务在同一个到范围内插入了数据,这时原来的事务再次查询同个范围的数据,就会读到另一个事务插入的新数据。这种现象称为幻读。但是Innodb的这个级别不会有幻读,因为它使用了临键锁(记录锁+间隙锁),会把查询范围内,存在的数据加上记录锁,不存在的数据范围加了间隙锁。这样其他事务想插入数据,就需要先获取锁。

但是另一种情况也会出现不可重复度。例如,有一条记录a=1。事务A先开启查询到a=1,事务B先执行a=a+1,并提交事务。这时事务A也执行a=a+1,再查询a,得到的结果是3而不是2。原因是update操作是先读取再更新记录,读取方式是当前读,即会读到最新的数据状态。所以事务A在更新a的时候,a已经等于2,然后被当前事务改成3。这时,事务再取读a值就是3。

序列化

序列化就是通过加锁的方式一个个执行事务,不存在可见性问题。

MVCC

对于读已提交和可重复读这两个隔离级别,Innodb使用了无锁读的技术MVCC和读视图,来提升查询性能。MVCC会在记录被修改时记录多个版本的数据,其实是一条最新版本的数据,然后跟着一串undo log。其他事务在开启一致性读后,根据事务ID在读视图里查询可见的数据版本。

这两个隔离级别的区别在于,读已提交是每次执行查询语句之前,都会重新创建读视图,这就会每次读到最近的已提交记录。可重复读是在第一次执行查询语句的时候创建读视图,这样能保证后面读到的数据是一样的。

读视图

MVCC里不同版本数据对事务的可见性由读视图来控制,读视图主要是一组事务ID,分为已提交事务、活跃事务、不可见事务三部分。

  • 已提交事务是指在当前事务开启的时刻,这些事务已经提交。这部分事务的变更对当前事务都是可见的。比当前活跃事务里最小的事务ID还小的事务,必然是已提交事务。在最小的事务ID和已分配的最大事务之间的非活跃事务,也算已提交事务。
  • 活跃事务是指当前事务开启的时刻,还未提交的事务。这部分事务的变更对当前事务都是不可见的。当前还活跃的事务ID集合。
  • 不可见事务是指当前事务开启的时刻,还不存在的事务。这部分事务的变更对当前事务都是不可见的。比当前系统已分配的最大事务ID还大的事务,必然是不可见事务。

持久性

持久性是指把数据变更写入磁盘,实现持久化的目的。Innodb使用AWL(ahead write log)方式,在事务提交的时候先把变更写入redo log,然后再同步到磁盘。

同步到磁盘策略有三种,由参数innodb_flush_log_at_trx_commit控制:

0:每秒写入日志和磁盘

1:每次事务提交时,都会将数据写入磁盘(默认)

2:每次事务提交会写入日志,每秒将日志写入磁盘


http://www.kler.cn/news/157459.html

相关文章:

  • C/C++ 原生套接字抓取FTP数据包
  • 【Cadence Allegro17.4】
  • nginx部署和安装-后端程序多端口访问-后端代理设置
  • Python实现FA萤火虫优化算法优化卷积神经网络分类模型(CNN分类算法)项目实战
  • 基于Eclipse+Mysql+Tomcat开发的 教学评价管理系统
  • using meta-SQL 使用元SQL 六
  • mfc项目设置软件版本
  • Unity Canvas、Canvas Scaler、Graphic Raycaster、EventSystem 组件详解
  • 分享 | 顶刊高质量论文插图配色(含RGB值及16进制HEX码)(第一期)
  • 基于SSM的图书馆管理系统的设计与实现
  • 【论文阅读】1 SkyChain:一个深度强化学习的动态区块链分片系统
  • 【滤波第二期】中值滤波的原理和C代码
  • 【开源】基于Vue和SpringBoot的音乐偏好度推荐系统
  • 跨网文件摆渡系统:安全、可控的数字传输桥梁
  • MyBatis查询优化:枚举在条件构建中的妙用
  • 写给初学者的 HarmonyOS 教程 -- 状态管理(@State/@Prop/@Link 装饰器)
  • linux 应用开发笔记---【标准I/O库/文件属性及目录】
  • PTA 一维数组7-3出生年(本题请你根据要求,自动填充“我出生于y年,直到x岁才遇到n个数字都不相同的年份”这句话)
  • C++算法入门练习——最大连续子序列和
  • vue2+electron桌面端一体机应用
  • golang实现函数yamlToStruct(infile,outFile)
  • 如何拆解Unity 2022.3版本的AssetBundle
  • GB/T 29734.1-2013 铝木复合门窗检测
  • 基于SSM的老年公寓信息管理的设计与实现
  • python提取通话记录中的时间信息
  • 翻译: 生成式人工智能的工作原理How Generative AI works
  • 如何使用Cloudreve搭建本地云盘系统并实现随时远程访问
  • VSCode搭建STM32开发环境
  • LLM之Agent(三):HuggingGPT根据用户需求自动调用Huggingface合适的模型
  • 数据库系统概论期末经典大题讲解(用关系代数进行查询)