mysql怎么保证原子性 mysql保证原子性更新

每日一问-常见MySQL面试问题3什么是数据库事务 , MySQL 为什么会使用 InnoDB 作为默认选项?
1.原子性(一个原子事务中的所有操作要么全部成功,要么全部失败) 实现主要基于undo log(回滚日志)
2.一致性(数据库总是从一个一致性的状态转换到另一个一致性的状态)
3. 隔离性(针对并发事务而言 , 事务必须在不干扰其他进程或事务的前提下独立执行)
4.持久性(一旦事务提交成功,它对于数据的修改就会永久保存到数据库中)
也就是mysql怎么保证原子性我们常说的事务ACID,这样才能保证事务中数据的正确性 。
InnoDB支持事务安全,InnoDB支持表、行(默认)级锁 , 而MyISAM支持表级锁mysql怎么保证原子性;
mysql 核心内容-上1、SQL语句执行流程
MySQL大体上可分为Server层和存储引擎层两部分 。
Server层:
连接器:TCP握手后服务器来验证登陆用户身份,A用户创建连接后,管理员对A用户权限修改了也不会影响到已经创建的链接权限,必须重新登陆 。
查询缓存:查询后的结果存储位置,MySQL8.0版本以后已经取消 , 因为查询缓存失效太频繁 , 得不偿失 。
分析器:根据语法规则,判断你输入的这个SQL语句是否满足MySQL语法 。
优化器:多种执行策略可实现目标,系统自动选择最优进行执行 。
执行器:判断是否有权限,将最终任务提交到存储引擎 。
存储引擎层
负责数据的存储和提取 。其架构模式是插件式的 , 支持InnoDB、MyISAM、Memory等多个存储引擎 。现在最常用的存储引擎是InnoDB,它从MySQL 5.5.5版本开始成为了默认存储引擎(经常用的也是这个) 。
SQL执行顺序
2、BinLog、RedoLog、UndoLog
BinLog
BinLog是记录所有数据库表结构变更(例如create、alter table)以及表数据修改(insert、update、delete)的二进制日志,主从数据库同步用到的都是BinLog文件 。BinLog日志文件有三种模式 。
STATEMENT 模式
内容:binlog 记录可能引起数据变更的 sql 语句
优势:该模式下,因为没有记录实际的数据,所以日志量很少 IO 都消耗很低,性能是最优的
劣势:但有些操作并不是确定的,比如 uuid() 函数会随机产生唯一标识,当依赖 binlog 回放时,该操作生成的数据与原数据必然是不同的,此时可能造成无法预料的后果 。
ROW 模式
内容:在该模式下,binlog 会记录每次操作的源数据与修改后的目标数据 , StreamSets就要求该模式 。
优势:可以绝对精准的还原 , 从而保证了数据的安全与可靠,并且复制和数据恢复过程可以是并发进行的
【mysql怎么保证原子性 mysql保证原子性更新】 劣势:缺点在于 binlog 体积会非常大 , 同时,对于修改记录多、字段长度大的操作来说,记录时性能消耗会很严重 。阅读的时候也需要特殊指令来进行读取数据 。
MIXED 模式
内容:是对上述STATEMENT 跟 ROW 两种模式的混合使用 。
细节:对于绝大部分操作,都是使用 STATEMENT 来进行 binlog 没有记录,只有以下操作使用 ROW 来实现:表的存储引擎为 NDB,使用了uuid() 等不确定函数,使用了 insert delay 语句 , 使用了临时表
主从同步流程:
1、主节点必须启用二进制日志,记录任何修改了数据库数据的事件 。
2、从节点开启一个线程(I/O Thread)把自己扮演成 mysql 的客户端,通过 mysql 协议,请求主节点的二进制日志文件中的事件。
3、主节点启动一个线程(dump Thread),检查自己二进制日志中的事件,跟对方请求的位置对比,如果不带请求位置参数,则主节点就会从第一个日志文件中的第一个事件一个一个发送给从节点 。
4、从节点接收到主节点发送过来的数据把它放置到中继日志(Relay log)文件中 。并记录该次请求到主节点的具体哪一个二进制日志文件内部的哪一个位置(主节点中的二进制文件会有多个) 。
5、从节点启动另外一个线程(sql Thread ) , 把 Relay log 中的事件读取出来,并在本地再执行一次 。
mysql默认的复制方式是异步的,并且复制的时候是有并行复制能力的 。主库把日志发送给从库后不管了,这样会产生一个问题就是假设主库挂了 , 从库处理失败了,这时候从库升为主库后 , 日志就丢失了 。由此产生两个概念 。
全同步复制
主库写入binlog后强制同步日志到从库,所有的从库都执行完成后才返回给客户端 , 但是很显然这个方式的话性能会受到严重影响 。
半同步复制
半同步复制的逻辑是这样,从库写入日志成功后返回ACK确认给主库,主库收到至少一个从库的确认就认为写操作完成 。
还可以延伸到由于主从配置不一样、主库大事务、从库压力过大、网络震荡等造成主备延迟 , 如何避免这个问题?主备切换的时候用可靠性优先原则还是可用性优先原则?如何判断主库Crash了?互为主备的情况下如何避免主备循环复制?被删库跑路了如何正确恢复?( o )… 感觉越来越扯到DBA的活儿上去了 。
RedoLog
可以先通过下面demo理解:
饭点记账可以把账单写在账本上也可以写在粉板上 。有人赊账或者还账的话,一般有两种做法:
1、直接把账本翻出来,把这次赊的账加上去或者扣除掉 。
2、先在粉板上记下这次的账,等打烊以后再把账本翻出来核算 。
生意忙时选后者,因为前者太麻烦了 。得在密密麻麻的记录中找到这个人的赊账总额信息,找到之后再拿出算盘计算,最后再将结果写回到账本上 。
同样在MySQL中如果每一次的更新操作都需要写进磁盘 , 然后磁盘也要找到对应的那条记录,然后再更新 , 整个过程IO成本、查找成本都很高 。而粉板和账本配合的整个过程就是MySQL用到的是Write-Ahead Logging 技术,它的关键点就是先写日志,再写磁盘 。此时账本 = BinLog , 粉板 = RedoLog 。
1、 记录更新时,InnoDB引擎就会先把记录写到RedoLog(粉板)里面,并更新内存 。同时 , InnoDB引擎会在空闲时将这个操作记录更新到磁盘里面 。
2、 如果更新太多RedoLog处理不了的时候,需先将RedoLog部分数据写到磁盘,然后擦除RedoLog部分数据 。RedoLog类似转盘 。
RedoLog有write pos 跟checkpoint
write pos :是当前记录的位置 , 一边写一边后移,写到第3号文件末尾后就回到0号文件开头 。
check point:是当前要擦除的位置,也是往后推移并且循环的 , 擦除记录前要把记录更新到数据文件 。
write pos和check point之间的是粉板上还空着的部分,可以用来记录新的操作 。如果write pos追上checkpoint , 表示粉板满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把checkpoint推进一下 。
有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe 。redolog两阶段提交:为了让binlog跟redolog两份日志之间的逻辑一致 。提交流程大致如下:
1 prepare阶段 -- 2 写binlog -- 3 commit
当在2之前崩溃时,重启恢复后发现没有commit,回滚 。备份恢复:没有binlog。一致
当在3之前崩溃时,重启恢复发现虽没有commit,但满足prepare和binlog完整 , 所以重启后会自动commit 。备份:有binlog. 一致
binlog跟redolog区别:
redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用 。
redo log是物理日志,记录的是在某个数据页上做了什么修改;binlog是逻辑日志,记录的是这个语句的原始逻辑 , 比如给ID=2这一行的c字段加1 。
redo log是循环写的,空间固定会用完;binlog是可以追加写入的 。追加写是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志 。
UndoLog
UndoLog 一般是逻辑日志,主要分为两种:
insert undo log
代表事务在insert新记录时产生的undo log, 只在事务回滚时需要,并且在事务提交后可以被立即丢弃
update undo log
事务在进行update或delete时产生的undo log; 不仅在事务回滚时需要,在快照读时也需要;所以不能随便删除,只有在快速读或事务回滚不涉及该日志时,对应的日志才会被purge线程统一清除
3、MySQL中的索引
索引的常见模型有哈希表、有序数组和搜索树 。
哈希表:一种以KV存储数据的结构,只适合等值查询,不适合范围查询 。
有序数组:只适用于静态存储引擎 , 涉及到插入的时候比较麻烦 。可以参考Java中的ArrayList 。
搜索树:按照数据结构中的二叉树来存储数据,不过此时是N叉树(B 树) 。广泛应用在存储引擎层中 。
B 树比B树优势在于:
B树非叶子节点存储的只是索引,可以存储的更多 。B 树比B树更加矮胖 , IO次数更少 。
B树叶子节点前后管理,更加方便范围查询 。同时结果都在叶子节点,查询效率稳定 。
B 树中更有利于对数据扫描,可以避免B树的回溯扫描 。
索引的优点:
1、唯一索引可以保证每一行数据的唯一性
2、提高查询速度
3、加速表与表的连接
4、显著的减少查询中分组和排序的时间
5、通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能 。
索引的缺点:
1、创建跟维护都需要耗时
2、创建索引时 , 需要对表加锁 , 在锁表的同时,可能会影响到其他的数据操作
3、 索引需要磁盘的空间进行存储,磁盘占用也很快 。
4、当对表中的数据进行CRUD的时 , 也会触发索引的维护,而维护索引需要时间,可能会降低数据操作性能
索引设计的原则不应该:
1、索引不是越多越好 。索引太多,维护索引需要时间跟空间 。
2、 频繁更新的数据,不宜建索引 。
3、数据量小的表没必要建立索引 。
应该:
1、重复率小的列建议生成索引 。因为重复数据少,索引树查询更有效率 , 等价基数越大越好 。
2、数据具有唯一性,建议生成唯一性索引 。在数据库的层面,保证数据正确性
3、频繁group by、order by的列建议生成索引 。可以大幅提高分组和排序效率
4、经常用于查询条件的字段建议生成索引 。通过索引查询,速度更快
索引失效的场景
1、模糊搜索:左模糊或全模糊都会导致索引失效,比如'%a'和'%a%' 。但是右模糊是可以利用索引的,比如'a%'。
2、隐式类型转换:比如select * from t where name = xxx , name是字符串类型,但是没有加引号,所以是由MySQL隐式转换的,所以会让索引失效 3、当语句中带有or的时候:比如select * from t where name=‘sw’ or age=14
4、不符合联合索引的最左前缀匹配:(A,B,C)的联合索引,你只where了C或B或只有B,C
关于索引的知识点:
主键索引:主键索引的叶子节点存的是整行数据信息 。在InnoDB里 , 主键索引也被称为聚簇索引(clustered index) 。主键自增是无法保证完全自增的哦,遇到唯一键冲突、事务回滚等都可能导致不连续 。
唯一索引:以唯一列生成的索引,该列不允许有重复值,但允许有空值(NULL)
普通索引跟唯一索引查询性能:InnoDB的数据是按数据页为单位来读写的,默认每页16KB,因此这两种索引查询数据性能差别微乎其微 。
change buffer:普通索引用在更新过程的加速,更新的字段如果在缓存中,如果是普通索引则直接更新即可 。如果是唯一索引需要将所有数据读入内存来确保不违背唯一性,所以尽量用普通索引 。
非主键索引:非主键索引的叶子节点内容是主键的值 。在InnoDB里,非主键索引也被称为二级索引(secondary index)
回表:先通过数据库索引扫描出数据所在的行,再通过行主键id取出索引中未提供的数据 , 即基于非主键索引的查询需要多扫描一棵索引树 。
覆盖索引:如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为覆盖索引 。
联合索引:相对单列索引,组合索引是用多个列组合构建的索引,一次性最多联合16个 。
最左前缀原则:对多个字段同时建立的组合索引(有顺序,ABC,ACB是完全不同的两种联合索引) 以联合索引(a,b,c)为例,建立这样的索引相当于建立了索引a、ab、abc三个索引 。另外组合索引实际还是一个索引,并非真的创建了多个索引,只是产生的效果等价于产生多个索引 。
索引下推:MySQL 5.6引入了索引下推优化,可以在索引遍历过程中,对索引中包含的字段先做判断,过滤掉不符合条件的记录,减少回表字数 。
索引维护:B 树为了维护索引有序性涉及到页分裂跟页合并 。增删数据时需考虑页空间利用率 。
自增主键:一般会建立与业务无关的自增主键,不会触发叶子节点分裂 。
延迟关联:通过使用覆盖索引查询返回需要的主键 , 再根据主键关联原表获得需要的数据 。
InnoDB存储: * .frm文件是一份定义文件 , 也就是定义数据库表是一张怎么样的表 。*.ibd文件则是该表的索引,数据存储文件,既该表的所有索引树,所有行记录数据都存储在该文件中 。
MyISAM存储:* .frm文件是一份定义文件,也就是定义数据库表是一张怎么样的表 。* .MYD文件是MyISAM存储引擎表的所有行数据的文件 。* .MYI文件存放的是MyISAM存储引擎表的索引相关数据的文件 。MyISAM引擎下 , 表数据和表索引数据是分开存储的 。
MyISAM查询:在MyISAM下,主键索引和辅助键索引都属于非聚簇索引 。查询不管是走主键索引,还是非主键索引,在叶子结点得到的都是目的数据的地址,还需要通过该地址,才能在数据文件中找到目的数据 。
PS:InnoDB支持聚簇索引 , MyISAM不支持聚簇索引
4、SQL事务隔离级别
ACID的四个特性
原子性(Atomicity):把多个操作放到一个事务中,保证这些操作要么都成功,要么都不成功
一致性(Consistency):理解成一串对数据进行操作的程序执行下来,不会对数据产生不好的影响,比如凭空产生,或消失
隔离性(Isolation,又称独立性):隔离性的意思就是多个事务之间互相不干扰,即使是并发事务的情况下,他们只是两个并发执行没有交集,互不影响的东西;当然实现中,也不一定需要这么完整隔离性,即不一定需要这么的互不干扰,有时候还是允许有部分干扰的 。所以MySQL可以支持4种事务隔离性
持久性(Durability):当某个操作操作完毕了 , 那么结果就是这样了,并且这个操作会持久化到日志记录中
PS:ACID中C与CAP定理中C的区别
ACID的C着重强调单数据库事务操作时 , 要保证数据的完整和正确性,数据不会凭空消失跟增加 。CAP 理论中的C指的是对一个数据多个备份的读写一致性
事务操作可能会出现的数据问题
1、脏读(dirty read):B事务更改数据还未提交 , A事务已经看到并且用了 。B事务如果回滚 , 则A事务做错了
2、 不可重复读(non-repeatable read):不可重复读的重点是修改: 同样的条件, 你读取过的数据, 再次读取出来发现值不一样了,只需要锁住满足条件的记录
3、 幻读(phantom read):事务A先修改了某个表的所有纪录的状态字段为已处理,未提交;事务B也在此时新增了一条未处理的记录,并提交了;事务A随后查询记录,却发现有一条记录是未处理的造成幻读现象,幻读仅专指新插入的行 。幻读会造成语义上的问题跟数据一致性问题 。
4、 在可重复读RR隔离级别下,普通查询是快照读,是不会看到别的事务插入的数据的 。因此,幻读在当前读下才会出现 。要用间隙锁解决此问题 。
在说隔离级别之前,你首先要知道,你隔离得越严实,效率就会越低 。因此很多时候,我们都要在二者之间寻找一个平衡点 。SQL标准的事务隔离级别由低到高如下: 上图从上到下的模式会导致系统的并行性能依次降低,安全性依次提高 。
读未提交:别人改数据的事务尚未提交 , 我在我的事务中也能读到 。
读已提交(Oracle默认):别人改数据的事务已经提交,我在我的事务中才能读到 。
可重复读(MySQL默认):别人改数据的事务已经提交,我在我的事务中也不去读,以此保证重复读一致性 。
串行:我的事务尚未提交,别人就别想改数据 。
标准跟实现:上面都是关于事务的标准,但是每一种数据库都有不同的实现,比如MySQL InnDB 默认为RR级别,但是不会出现幻读 。因为当事务A更新了所有记录的某个字段,此时事务A会获得对这个表的表锁,因为事务A还没有提交,所以事务A获得的锁没有释放,此时事务B在该表插入新记录 , 会因为无法获得该表的锁,则导致插入操作被阻塞 。只有事务A提交了事务后,释放了锁,事务B才能进行接下去的操作 。所以可以说 MySQL的RR级别的隔离是已经实现解决了脏读,不可重复读和幻读的 。
5、MySQL中的锁
无论是Java的并发编程还是数据库的并发操作都会涉及到锁,研发人员引入了悲观锁跟乐观锁这样一种锁的设计思想 。
悲观锁:
优点:适合在写多读少的并发环境中使用,虽然无法维持非常高的性能,但是在乐观锁无法提更好的性能前提下,可以做到数据的安全性
缺点:加锁会增加系统开销,虽然能保证数据的安全,但数据处理吞吐量低,不适合在读书写少的场合下使用
乐观锁:
优点:在读多写少的并发场景下,可以避免数据库加锁的开销,提高DAO层的响应性能,很多情况下ORM工具都有带有乐观锁的实现,所以这些方法不一定需要我们人为的去实现 。
缺点:在写多读少的并发场景下,即在写操作竞争激烈的情况下,会导致CAS多次重试,冲突频率过高,导致开销比悲观锁更高 。
实现:数据库层面的乐观锁其实跟CAS思想类似,通数据版本号或者时间戳也可以实现 。
数据库并发场景主要有三种:
读-读:不存在任何问题,也不需要并发控制
读-写:有隔离性问题,可能遇到脏读,幻读 , 不可重复读
写-写:可能存更新丢失问题,比如第一类更新丢失,第二类更新丢失
两类更新丢失问题:
第一类更新丢失:事务A的事务回滚覆盖了事务B已提交的结果 第二类更新丢失:事务A的提交覆盖了事务B已提交的结果
为了合理贯彻落实锁的思想,MySQL中引入了杂七杂八的各种锁:
锁分类
MySQL支持三种层级的锁定,分别为
表级锁定
MySQL中锁定粒度最大的一种锁,最常使用的MYISAM与INNODB都支持表级锁定 。
页级锁定
是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁,表级锁速度快,但冲突多,行级冲突少,但速度慢 。所以取了折衷的页级,一次锁定相邻的一组记录 。
行级锁定
Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁 。行级锁能大大减少数据库操作的冲突 。其加锁粒度最小,但加锁的开销也最大行级锁不一定比表级锁要好:锁的粒度越细,代价越高,相比表级锁在表的头部直接加锁,行级锁还要扫描找到对应的行对其上锁,这样的代价其实是比较高的,所以表锁和行锁各有所长 。
MyISAM中的锁
虽然MySQL支持表 , 页,行三级锁定 , 但MyISAM存储引擎只支持表锁 。所以MyISAM的加锁相对比较开销低,但数据操作的并发性能相对就不高 。但如果写操作都是尾插入 , 那还是可以支持一定程度的读写并发
从MyISAM所支持的锁中也可以看出 , MyISAM是一个支持读读并发 , 但不支持通用读写并发,写写并发的数据库引擎,所以它更适合用于读多写少的应用场合,一般工程中也用的较少 。
InnoDB中的锁
该模式下支持的锁实在是太多了,具体如下:
共享锁和排他锁 (Shared and Exclusive Locks)
意向锁(Intention Locks)
记录锁(Record Locks)
间隙锁(Gap Locks)
临键锁 (Next-Key Locks)
插入意向锁(Insert Intention Locks)
主键自增锁 (AUTO-INC Locks)
空间索引断言锁(Predicate Locks for Spatial Indexes)
举个栗子,比如行锁里的共享锁跟排它锁:lock in share modle 共享读锁:
为了确保自己查到的数据没有被其他的事务正在修改,也就是说确保查到的数据是最新的数据,并且不允许其他人来修改数据 。但是自己不一定能够修改数据,因为有可能其他的事务也对这些数据使用了 in share mode 的方式上了S 锁 。如果不及时的commit 或者rollback 也可能会造成大量的事务等待 。
for update排它写锁:
为了让自己查到的数据确保是最新数据 , 并且查到后的数据只允许自己来修改的时候,需要用到for update 。相当于一个 update 语句 。在业务繁忙的情况下 , 如果事务没有及时的commit或者rollback 可能会造成其他事务长时间的等待,从而影响数据库的并发使用效率 。
Gap Lock间隙锁:
1、行锁只能锁住行 , 如果在记录之间的间隙插入数据就无法解决了 , 因此MySQL引入了间隙锁(Gap Lock) 。间隙锁是左右开区间 。间隙锁之间不会冲突 。
2、间隙锁和行锁合称NextKeyLock,每个NextKeyLock是前开后闭区间 。
间隙锁加锁原则(学完忘那种):
1、加锁的基本单位是 NextKeyLock , 是前开后闭区间 。
2、查找过程中访问到的对象才会加锁 。
3、索引上的等值查询 , 给唯一索引加锁的时候,NextKeyLock退化为行锁 。
4、索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,NextKeyLock退化为间隙锁 。
5、唯一索引上的范围查询会访问到不满足条件的第一个值为止 。
mysql 事务能保证原子性吗原子性,一个事务 要么完全提交 要么完全回滚 , 不会介于2者之间 。一致性,一个查询发起后 , 不管数据发生了多少变化 多少事务,查询结果应当为发起查询时间一致的数据
mysql的四大特性1、原子性:在整个操作的事务中,要么全部成功 , 要么全部失败 。
2、隔离性:所谓隔离性,就是每个事务执行的时候,相互之间不会受到影响,都是单独的事务 。
3、一致性:也就是说事务在执行之后,必须和之前的数据保持一致 。
4、持久性:事务一旦提交,就会持久化到数据库中,不能回滚 。
mysql事务的四大特性是什么?1、原子性(Atomicity)原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚 , 因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响 。
2、 一致性(Consistency)一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态 。
拿转账来说 , 假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性 。
3、隔离性(Isolation)隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离 。
即要达到这么一种效果:对于任意两个并发的事务T1和T2 , 在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始 , 这样每个事务都感觉不到有其他事务在并发地执行 。
4、持久性(Durability)持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的 , 即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作 。
扩展资料
MyISAMMySQL5.0之前的默认数据库引擎,最为常用 。拥有较高的插入,查询速度 , 但不支持事务InnoDB事务型数据库的首选引擎,支持ACID事务,支持行级锁定,MySQL5.5起成为默认数据库引擎BDB源自BerkeleyDB , 事务型数据库的另一种选择,支持Commit和Rollback等其他事务特性Memory所有数据置于内存的存储引擎,拥有极高的插入,更新和查询效率 。
但是会占用和数据量成正比的内存空间 。并且其内容会在MySQL重新启动时丢失Merge将一定数量的MyISAM表联合而成一个整体 , 在超大规模数据存储时很有用Archive非常适合存储大量的独立的,作为历史记录的数据 。
因为它们不经常被读取 。Archive拥有高效的插入速度,但其对查询的支持相对较差Federated将不同的MySQL服务器联合起来,逻辑上组成一个完整的数据库 。非常适合分布式应用Cluster/NDB高冗余的存储引擎,用多台数据机器联合提供服务以提高整体性能和安全性 。适合数据量大,安全和性能要求高的应用
undolog实现事务原子性 , redolog实现事务的持久性undolog可以实现事务mysql怎么保证原子性的原子性mysql怎么保证原子性,还可以用来实现MVCC 。其原理是mysql怎么保证原子性 , (开启事务后)在操作任何数据前,先将原数据备份到undolog,然后对数据进行修改,如果此过程中出现异常,或执行了rollback语句 , 可利用undolog中备份的数据恢复到事务开始之前的状态 。
假设有A、B两个数据,值分别为1,2 。进行 2的事务操作 。
A.事务开始.
B.记录A=1到undo log.
C.修改A=3.
D.记录B=2到undo log.
E.修改B=4.
F.将undo log写到磁盘 。
G.将数据写到磁盘 。
H.事务提交
对于数据的操作,都是先读到内存中,然后在内存中修改 , 最后将数据写到磁盘 。
之所以能保证原子性,是因为mysql怎么保证原子性:
A. 更新数据前记录Undo log 。
B. 为了保证持久性 , 必须将数据在事务提交前写到磁盘 。只要事务成功提交,数据必然已经持久化 。
C. Undo log必须先于数据持久化到磁盘 。如果在G,H之间系统崩溃,undo log是完整的,可以用来回滚事务 。
D. 如果在A-F之间系统崩溃,因为数据没有持久化到磁盘 。所以磁盘上的数据还是保持在事务开始前的状态 。
缺点:每个事务提交前将数据和Undo Log写入磁盘,这样会导致大量的磁盘IO,因此性能很低 。
所以,为了提升性能,可以在写数据到磁盘前,先写redolog,这就是wal预写日志机制,这样先写redolog日志,数据只需先写到内存,因为redolog是顺序写,而数据落盘则是随机写,要慢得多 。这样,当系统崩溃时,虽然数据没有持久化 , 但有redolog撑着,数据也不会丢 。(innodb_flush_log_at_trx_commit这个参数设置为2时,那么redolog每次不需落盘 , 而是写到os cache中(一定时间后再flush到磁盘),这样性能又大大提升,只要操作系统不宕 , 即便mysql宕了,数据也不会丢)
UndoRedo事务的简化过程
A.事务开始.
B.记录A=1到undo log.
C.修改A=3.
D.记录A=3到redo log.
E.记录B=2到undo log.
F.修改B=4.
G.记录B=4到redo log.
H.将redo log写入磁盘 。
I.事务提交
通过undo保证事务的原子性,redo保证持久性 。
但是?。。』谝陨系墓蹋?mysql一个事务操作依旧十分繁琐 , 这也就是其在并发场景下需借助于nosql来提升性能
redolog和undolog属于innodb,而在mysql的server层还有一个binlog,其作用是误操作后需要靠它来恢复数据以及主从复制,mysql在update一行数据的时候:
1.执行器先找引擎取id=n这一行 , id是主键,引擎直接用树搜索到这一行
2.执行器拿到引擎给的行数据,把这个值加1,得到新的一行数据,再调用引擎接口写入这行新数据
3.引擎将这行数据更新到内存中,同时将这个更新操作记录到redolog中,此时redolog处于prepare状态,然后告知执行器执行完成,随时可以提交事务
4.执行器生成这个操作的binlig,并写入磁盘
5.执行器调用引擎的提交事务接口 , 引擎吧刚刚写入的redolog改成提交(commit)状态,更新完成
将redolog的写入拆成两个步骤,prepare和commit,这就是两阶段提交,其目的是为了让两份日志(redolog和binlog)之间的逻辑一致
这两个日志有三点不同:
1.redolog是innodb特有,binlog是mysql server层实现的,所有引擎都可以使用,
2.redolog是物理日志,记录的是在某个数据页上做了什么修改 , binlog是逻辑日志,记录的是这个语句的原始逻辑,
3.redolog是循环写的,空间固定会用完,binlog是可以追加写入的,追加写是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志 。
redolog和binlog互相是不可替代的,redolog的作用是提升数据写入时的性能 , 并保证事务的持久化特性,以及崩溃恢复的能力 , 而binlog 是无法支持崩溃恢复,因为它没有能力恢复“数据页” 。而binlog也有着redolog无法替代的功能,一个是归档 。redo log 是循环写,写到末尾是要回到开头继续写的 。这样历史日志没法保留,redolog 也就起不到归档的作用 。还有很多公司有异构系统中使用到的组件(比如es , redis等),这些系统就靠消费 MySQL 的 binlog 来更新自己的数据 。关掉 binlog 的话,这些下游系统就没法输入了 。总之,由于现在包括 MySQL 高可用在内的很多系统机制都依赖于 binlog , 所以“鸠占鹊巢”redo log 还做不到 。
关于mysql怎么保证原子性和mysql保证原子性更新的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站 。

    推荐阅读