在学习数据库相关的知识时总会听到脏读、幻读、不可重复读等导致每个事务读取的数据不一致而产生紊乱。
1、脏读:当事务A正在访问数据并进行修改,但是没有事务提交,这时事务B也访问这个数据读到事务A未提交的数据
2、幻读:事务A第一次查询表数据总和,事务B新增数据并提交,事务A第二次查询得到表数据总和前后不一致而产生一种幻觉。
3、不可重复读:事务A查询了一条数据,事务B修改并提交,事务A在此读取的时候发现前后两次读取不一致,成为不可重复读。
所以当多个事务同时执行会存在上述问题为了解决这种现象,mysql就有了隔离级别,但是隔离级别越彻底也会导致性能的问题所以需要找到平衡点。
以下是Mysql采取了四种隔离级别
1. 读未提交: 事务没提交,可被别的事务看到
2. 读提交 (RR):事务提交才被别的事务看到
3. 可重复读 (RC):事务在执行过程,看到的数据和事务启动时看到的数据一致。未提交事务时对其他事务不可见
4.串行化:同一条记录,有读锁和写锁存在,当出现读写冲突存在,后访问的事务必须等前一个事物执行完成(事务的先后)
Mysql默认的事务隔离级别是Repeated Read(RR),达到的效果读取到数据都是其他事务已经提交的,同一个事物相同的读取得到的结果一直,不会出现insert幻读。
那么读提交和可串行化这种事务隔离级别到底是怎么实现的?
InnoDB里每个事物其实都有唯一的 事务ID是在事务开始时向InnoDB的事务系统申请严格递增。每次事务更新数据,都会生成一个新版本数据,这样一条数据记录会有多个版本每个版本都有自己trx_id,通过数组进行维护,将已经提交的事务ID和未提交的事务ID进行区分来确定数据版本的可见性。 InnoDB则利用数据多版本特性达到了读写并发。
对于多事务写操作,mysql则采取先读后写操作(当前读) ,也就是说事务A先进行修改数据但未提交事务B进行修改数据,这个时候事务A其实对写操作进行加锁,事务B则进行等待,直到事务A释放事务B读到最新版本数据。
那么读提交RR和可重复读RC又有什么区别呢?
InnoDB的RR和RC在事务提交时都会创建一个视图,RC是在事务启动的时候进行创建之后事务内都是共用这个一致性视图的,RR则在每个sql执行开始的时候进行创建的。
如果事务出现异常进行事务回滚,Mysql会做些什么?
我们都知道Mysql在修改一条记录首先将数据在内存中进行更新,然后redolog进行记录并置为prepare状态,告知Mysql执行器执行完成调用commit接口,这时执行器生成操作日志在binlog里并写入磁盘,执行器最终告知redolog改成提交状态(Mysql的两阶段提交)完成整个操作。
其实在事务执行时也会在undolog存放,如果事务发生回滚或异常可以利用undo日志,撤销未提交的事务对数据库产生的影响。
为什么写日志落盘会产生写磁盘操作,为什么还这么快呢?
其实Mysql会为binlog分配一块内存,每个线程都会维护,在事务执行开始的时候先将数据写入Mysql内存,然后把log在写入文件系统的page cache中,最终才将数据持久到磁盘里,整个事务完成后会清空binlog的cache。
mysql事务提交(组提交)Mysql采取并行事务提交通过sync_binlog控制写缓存write和同步到磁盘中fsyn,当sync_binlog=0只写缓存,sync_binlog=1每次事务提交后都执行fsyn,sync_binlog=n :每次事务提交累积到N个事务后一起fsyn,常见将N设置为100-1000
网友评论