MySQL是如何实现事务的?
实现事务的ACID主要靠MySQL的四个核心组件,分别是: Redo log、Undo log、锁、MVCC。 Redo log保证了事务的持久性,在修改前先写到Redo log中,然后再写到磁盘数据页里,这样子就算写到磁盘里的时候宕机了,之后还可以重新根据Redo log来恢复数据。 Undo log保证了事务的原子性,修改前,会先把原值存到Undo log中,事务回滚的时候,按照undo log来把数据回复回去,这样子保证了事务要么是全部执行完,要不就全部不执行。 锁机制和MVCC保证了隔离型,其中锁机制解决了并发修改的问题,它会在一个事务修改时上锁,另外的事务要等锁释放才能修改,防止出现事务执行过程中被别的事务修改的问题。MVCC则保证了事务的读写并发问题,在进行读操作的时候不靠加锁,而是通过undo log里的版本链找到自己应该看到的数据版本。这样子写的同时也可以读,因为操作的不是同一个内容。 而这些加起来共同的效果实现了一致性,也就是数据按照预期的情况发生变化,不出现不一致的情况。
问题:
innodb_flush_log_at_trx_commit设成0和2有什么区别?
这个属性的值控制着什么情况下把redo log从log buffer刷到硬盘中,设成0表示每过一秒刷一次,如果在这个过程中mysql突然挂了,那么就会丢掉1秒的数据;设成2表示将缓存提交给系统,存在系统缓存,让系统帮忙写,如果mysql挂了,数据也不会丢失,但是机器挂了的话数据会丢失。初次之外,还可以设成1,这个是每次事务提交都会直接把redo log写入硬盘,最安全但是性能也是三个里面最差的。
MVCC能解决幻读问题吗?
mvcc只能解决快照读时的幻读问题,解决不了当前读的幻读。快照读依靠mvcc可以去重复读取某一个快照的数据,因为这个快照的内容不会被改变,因此不会发送幻读问题。而当前读的幻读需要依靠间隙锁来在读取的时候将数据行锁住来解决。
undo log什么时候会被清理?
undo log在没有事务需要用到它的时候才会被删除,具体是依靠Purge线程来判断的,它会找到系统里最老的ReadView,比这个ReadView还老的undo log才可以删除(这里是因为undo log用于记录原值和找到老快照的位置,如果某个快照是在undo log之后才生成的,就表明这个事务不需要看比这个快照还要之前的快照了,就可以安全删除比这个还要老的undo log)所以要避免长事务,因为长事务可能会导致undo log堆积。(在长事务运行的时候生成了一个ReadView,那么之后的所有undo log都不能删除,因为没办法保证他们是否修改了这个长事务需要读取的值,为了能够顺着链表找到当前长事务运行时对应的快照,它们就必须都保留下来,如果在长事务运行过程中执行了非常多的短事务就会导致堆积。)
为什么redo log要循环写而不是一直加?
因为redo log的目的是防止数据因为崩溃而丢失,用于崩溃恢复。当数据成功写入磁盘里之后,那些日志就没有作用了,因此采用循环写可以减少磁盘空间的占用,并且还有一个好处是,连续的磁盘空间顺序写性能更佳。(binlog是用于主从同步和数据恢复,因此需要保存所有的历史记录,就得一直加下去。)