事务
1.什么是事务?
事务就是要保证一组数据库操作要么全部成功,要么全部失败。MYSQL中,事务的支持是在引擎层实现的,InnoDB引擎是支持事务的,MYSQL原生的MyISAM引擎不支持事务。
隔离性和隔离级别
隔离性,即ACID特性中的I。
1.为什么需要隔离级别?
数据库上有多个事务同时执行时,可能会出现脏读、幻读、不可重复读等问题,通过隔离级别解决这些问题。隔离得越严实,效率越低,需要在隔离级别和效率之间找到平衡点。
2.隔离级别有哪些?
(1)读未提交
一个事务还未提交,这个事务做的变更就能被其他事务看见
(2)读提交
一个事务提交后,这个事务做的变更才能被其他事务看见
(3)可重复读
一个事务执行过程看到的数据,总是和这个事务启动时看到的数据时一样的。事务里更新记录是会加行锁的 。
(4)串行化
对于一行记录,读会加读锁,写会加写锁,出现读写冲突时,后访问的事务必须等前一个事务执行完成。 读操作之间时不冲突的 。
3.读提交级别下视图创建的时机时什么时候?
RC级别下,每个SQL语句前都会用 记录最新版本的数据(回滚段的最新段) 创建一个视图,所以一个事务已提交事能被其他事务看见的。RR级别下,这个视图时在事务创建时创建的。
4.事务的隔离级别是用什么来实现的?视图?
TODO
5.读未提交级别下,是直接返回记录上的最新值,这个值是哪里来的?
内存里,innodb 的 buffer pool,这个buffer pool是否可以理解为页缓存?TODO
6.什么是视图?
一条select返回的结果集是视图(虚拟表),我们这里说的视图,是InnoDB的一致性视图。TODO 可以看第8篇解释这两个概念的区别,这个视图的范围是整个库。
事务隔离是怎么实现的
通过MVCC实现的。以下的说明都是在可重复读的级别下的。
1.MVCC是什么?
多版本并发控制,同一条记录在系统中可以存在多个版本。
2.MVCC是怎么实现的?
每条记录在更新时都会记录一条回滚操作到回滚日志(undolog)里,记录上的最新值,通过回滚操作都可以得到前一个状态的值。不同时刻启动的事务会有不同的read-review,事务里要操作的记录需要执行事务创建时间之后所有的回滚日志才能得到这条记录在当前事务的值。
3.回滚日志不能一直保留,什么时候删除呢?
当没有事务需要用到这些回滚日志时,回滚日志会被删除。
4.什么时候不需要用到这些回滚日志呢?
当没有比这些回滚日志更早的read-view时,一个事务开启后,在事务提交或者回滚之前,所有更新产生的undolog都不能删除。
TODO 可以看第8篇
5.为什么不要使用长事务?
(1)长事务占用锁资源,可能会拖垮整个库
(2)长事务意味着事务用的read-view可能非常老,事务可能访问数据库里的任何数据,所以事务提交之前任何这个事务可能用到的回滚日志都需要保留,需要占用大量存储空间。
MYSQL 5.5及以前的版本,数据字典和回滚日志都是放在ibdata文件里的,事务提交后清除了回滚段,但是这个ibdata文件不会变小,清除的空间仅是可以分配给其他的数据进行存储,而不再被回滚段占用。
MYSQL5.6及之后的版本,数据字典和回滚日志可以存放在不同的文件。
事务的启动方式
1.通过语句显示启动事务和提交/回滚事务。通过语句beign或者start transaction启动事务,通过语句commit或者rollback提交或者回滚事务。
2.set autocommit=0关闭线程自动提交事务。如果只是执行一个select语句事务就启动了并且不会自动提交。
很多语言的第三方库都是使用连接池维持可复用的长链接保持和mysql的连接,默认连接成功后执行一个set autocommit=0命令,导致接下来的查询都在事务中。
3.如何查正在执行的长事务?
下面的SQL可以查执行超过60秒的长事务
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
如何避免长事务
业务开发:
1.确认是否使用了set autocommit=0,如果使用了就尝试把这个参数改成1。如何确认是否使用了?可以测试环境开启general_log来确认
2.确认是否有只读事务,即beign和commit/rollback之间的只有select语句。不需要使用事务。
3.业务连接数据库时,评估一下,通过SET MAX_EXECUTION_TIME命令控制每个语句执行的最长时间。
数据库端:
1.监控inndodb_schema.Innodb_trx表,设置长事务阈值,如果超过了就报警或者kill
2.在业务测试阶段输出所有的general_log,分析日志提前发现问题。
3.如果数据库是5.6版本或者更新的版本,把innodb_undo_tablespace设置为2。如果真的出现长事务导致回滚段过大,可以方便清理。
这个参数的说明:
innodb_undo_tablespaces是控制undo是否开启独立的表空间的参数 为0表示:undo使用系统表空间,即ibdata1 不为0表示:使用独立的表空间,一般名称为 undo001 undo002,存放地址的配置项为:innodb_undo_directory 一般innodb_undo_tablespaces 默认配置为0,innodb_undo_directory默认配置为当前数据目录
高质量问题
1.在没有显式开启事务的情况下,可不可以认为每个sql的执行都算是一个事务?
是
2.一个事务在执行到一半的时候宕机了,如何恢复?
在恢复的时候是不是先恢复redo,再根据redo构造undo回滚宕机前没有提交的事务。
3.两个RR级的事务同时启动,都是对同一个字段操作,系统起了两个互不影响的view,那事务的结果会不会被覆盖,直觉上肯定不会被覆盖,大家知道记录上会有锁,但这个锁和view是什么关系呢?
TODO可以看第七篇
4.读提交每次都要新建一个视图,而可重复读只建立一次,那么为什么读提交的效率要比可重复读高呢
一般我们说可重复的效率相对的低(其实也还好,不会低多少),
主要还是因为可重复读的锁范围可能更大(有gap lock),锁时间更长(事务结束才释放),影响并发度。TODO 其他隔离级别是什么情况