事务数据库的事务,可以是一个非常简单的SQL,也可以是一组sql构成的,事务是访问或者更新数据库的一个单元。
begincommit一个事务内的语句,要么全部成功,要么全部失败不存在部分成功,部分失败的情况
事务的四个特性原子性:一个事务内的任务要么全部执行成功,要不全部不执行一致性:事务的整个执行过程中,数据库的完整性的约束不能被破坏隔离性:事务的隔离性要求当前事务的操作,不会受到其他事务的影响持久性:事务一旦提交那么结果是持久性的,即使宕机,也不影响
Redo的作用
1、持久化数据
在数据库commit的时候,必须要保证redo的安全性,必须要保证redo已经落盘,才能返回提交成功的结果。redo是记录了Innodb数据库所有的数据变化,所以只要redo能落盘,数据就已经持久化,如果发生了宕机,在重启数据库后,可以通过redo直接进行数据库的恢复操作。
比对redo的lsn和数据的lsn,如果数据页的lsn比redo小,那么就需要通过redo对数据页进行重做,保证事务的特性。
2、效率提高性能
为什么在落盘的时候是提交redo到硬盘,而不是直接刷新脏块,主要原因
redo效率
1、脏块的数据量比较大,落盘脏块的话,一个块16KB,我们即使只修改一条数据,那么也需要整个脏快落盘,对于系统的IO压力很大,而redo记录的是数据库的修改的数据页的变化情况,而且
a.redo的落盘操作是顺序IO,性能较好
b.redo只记录数据页的改变情况,数据量很小
c.redo的数据库和硬盘块是一样的,IO效率高
注意:
redo落盘是持续在事务执行的整个过程中的,并不是commit的时候才进行redo落盘的操作,这样的目的在于redo的落盘和脏块的落盘是完全两个过程。
1、DML操作导致的页面变化,均需要记录Redo日志(物理日志);
2、在页面修改完成之后,在脏页刷出磁盘之前,写入Redo日志;
3、日志先行(WAL),日志一定比数据页先写回磁盘;
4、 聚簇索引/二级索引/Undo页面修改,均需要记录Redo日志;
undo作用1、回滚事务2、保证mvcc多版本高并发控制innodb把undo分两类1、新增(insert))2、修改undo(update del)
insert在事务执行完成后,回滚记录就可以丢掉了。但是对于更新和删除操作而言,在完成事务后,还需要为MVCC提供服务,这些日志就被放到一个history list,用于MVCC以及等待purge。undo日志的正确性是通过redo来保证的,所以在数据库恢复的时候,需要先恢复redo,在所有数据块都保证一致性的情况下,在进行undo的逻辑操作。
检查点(checkpoint)
检查点解决的问题
1. 缩短数据库恢复时间
2. 缓冲池不够用的时候,刷新脏页到磁盘
3. 重做日志不够用的时候,刷新脏页
当数据库发生宕机的时候,数据库不需要恢复所有的页面,因为检查点之前的页面都已经刷新回磁盘了。故数据库只需要对检查点以后的日志进行恢复,这就大大减少了恢复时间。
检查点类型sharp和fuzzysharp,关闭数据库的时候设置innodb_fast_shutdown=1,在关闭数据库的时候,会刷新所有脏页到数据库内。fuzzy checkpoint在数据库运行的时候,进行页面的落盘操作,不是全部落盘,是落盘一部分数据
mysql两个阶段提交存储引擎+server层提交存储引擎 redoserver binlogredo binlog 在事务的提交过程中, 要保证两个日志的事务的顺序是一致的。
先写binlog落盘--重做缓存--redo
MySQL二阶段提交流程:事务的提交主要分三个主要步骤:
1、Storage Engine(InnoDB) transaction prepare阶段:此时SQL已经成功执行,并生成xid信息及redo和undo的内存日志。
2、Binary log日志提交:write()将binary log内存日志数据写入文件系统缓存。fsync()将binary log文件系统缓存日志数据永久写入磁盘。
3、Storage Engine(InnoDB)内部提交:修改内存中事务对应的信息,并且将日志写入重做日志缓冲。调用fsync将确保日志都从重做日志缓冲写入磁盘。
一旦步骤2中的操作完成,就确保了事务的提交,即使在执行步骤3时数据库发送了宕机。此外需要注意的是,每个步骤都需要进行一次fsync操作才能保证上下两层数据的一致性。步骤2的fsync参数由sync_binlog控制,步骤2的fsync由参数innodb_flush_log_at_trx_commit控制。
事务隔离级别
read uncommited 未提交读容易产生脏读的问题,就是本事务读取到其他事务没有提交的数据,读取其他事务在内存中的脏块的数据。
修改隔离级别session级别修改global 修改set session transaction isolation level read uncommited;set global transaction isolation level ****;mysql默认的事务是自动提交的关闭自动提交set autocommit=0;session级别的参数
set session transaction isolation level read uncommitted;set autocommit=0;show variables like '%iso%';


session2读到了sessionq1中没有提交的数据,脏读


RC隔离级别set session transaction isolation level read committed;避免了脏读
select 在session1没有提交的情况下,没有查询到新插入数据,没有造成脏读


但是session1 commit之后,session2读到了不一样的数据

脏读(Drity Read):事务T1修改了一行数据,事务T2在事务T1提交之前读到了该行数据。
不可重复读(Non-repeatable read): 事务T1读取了一行数据。 事务T2接着修改或者删除了改行数据,当T1再次读取同一行数据的时候,读到的数据时修改之后的或者发现已经被删除。
幻读(Phantom Read): 事务T1读取了满足某条件的一个数据集,事务T2插入了一行或者多行数据满足了T1的选择条件,导致事务T1再次使用同样的选择条件读取的时候,得到了比第一次读取更多的数据集。
幻读和可重复读的区别
幻读更多的是针对于insert来说,即在一个事务之中,先后的两次select查询到了新的数据,新的数据来自于另一个事务的insert,一般称之为幻读,通过gap_lock来防止产生幻读(虽然record可以避免数据行被修改,但是却无法阻止insert,gap_lock锁定索引间隙,防止了在事务查询的范围内的insert情况)而可重复读,一般是针对于update和delete来说,可重复读采用了mvcc多版本控制来实现数据查询结果本身的不变。
RR 模式下避免幻读set session transaction isolation level repeatable read;
RR 模式下避免幻读set session transaction isolation level repeatable read;session1 session2begin begin update t1 allinsert 1 阻塞(保证不会有新的数据对update t1的结果产生影响) commit后,session1不再阻塞commit
-----------------------------------------------------------
RR模式下避免不可重复读set session transaction isolation level repeatable read;session1 session2begin begin select t1 mayday(查询是mayday)update t1 cjr(更新数据为cjr) select t1 mayday(查询还是mayday)commit select t1 mayday (依然mayday) commit select t1 cjr(再次查询是cjr了)




