日志
mysql服务器日志
- 错误日志:-log-err (记录启动,运行,停止mysql时出现的信息)
- 二进制日志:-log-bin (记录所有更改数据的语句,还用于复制,恢复数据库用)
- 查询日志:-log (记录建立的客户端连接和执行的语句)
- 慢查询日志: -log-slow-queries (记录所有执行超过long_query_time秒的所有查询)
- 更新日志: -log-update (二进制日志已经代替了老的更新日志,更新日志在MySQL 5.1中不再使用)
InnoDB事务日志
InnoDB事务日志包括:
- redo log :重做日志,提供前滚操作
- undo log :回滚日志,提供回滚日志
1.redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
2.undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录,undo log有两个作用:提供回滚和多个行版本控制(MVCC)。
- Redo Log:记录了数据操作在物理层面的修改,mysql中使用了大量缓存,修改操作时会直接修改内存,而不是立刻修改磁盘,事务进行中时会不断的产生redo log,在事务提交时进行一次flush操作,保存到磁盘中。当数据库或主机失效重启时,会根据redo log进行数据的恢复,如果redo log中有事务提交,则进行事务提交修改数据。
- Undo Log: 除了记录redo log外,当进行数据修改时还会记录undo log,undo log用于数据的撤回操作,它记录了修改的反向操作,比如,插入对应删除,修改对应修改为原来的数据,通过undo log可以实现事务回滚,并且可以根据undo log回溯到某个特定的版本的数据,实现MVCC
事务Transaction
概要
Mysql只有InnoDB引擎和BDB(5.1之后被收购)支持事务功能
事务主要包括:
- 开启事务:Start Transaction
- 事务结束:End Transaction
- 提交事务:Commit Transaction
- 回滚事务:Rollback Transaction
事务特征(ACID):
- 原子性(Atomicity): 事务是最小单位,不可再分
- 一致性(Consistency):事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败
- 隔离性(Isolation): 事务A和事务B之间具有隔离性
- 持久性(durability): 是事务的保证,事务终结的标志(内存的数据持久到硬盘文件中)
redo log用于保证事务持久性,原子性;undo log则是事务一致性,锁保证隔离性。
Mysql事务处理:
事务过程:
start transaction; //begin;语句 …… #一条或多条sql语句 commit;
start transaction标识事务开始,
commit提交事务,将执行结果写入到数据库。
如果sql语句执行出现问题,会调用rollback,回滚所有已经执行成功的sql语句,在commit之前也可以主动rollbak。
mysql默认自动提交,没有显式的start transaction,那么每一条sql语句都是一个事务。
如果autocommit被关闭,则所有sql被认为是一个事务,直到commit或者rollback。
事务并发问题:
- 脏读:当前事务(A)中可以读到其他事务(B)未提交的数据(脏数据)
- 不可重复读:在事务A中先后两次读取同一个数据,两次读取的结果不一样。脏读与不可重复读的区别在于:前者读到的是其他事务未提交的数据,后者读到的是其他事务已提交的数据。
- 幻读:在事务A中按照某个条件先后两次查询数据库,两次查询结果的条数不同。不可重复读与幻读的区别可以通俗的理解为:前者是数据变了,后者是数据的行数变了。
Mysq事务隔离级别:
- 读未提交(read-uncommitted):能发生脏读,不可重复读,幻读
- 读已提交(read-committed):能发生不可重复读,幻读
- 可重复读(repeatable read):能发生幻读,InnoDB不会发生任何并发问题
- 串行化(serializable):不会发生任何问题
Msql多版本并发控制MVCC:
MVCC通过乐观解决并发问题,只在读已提交和可重复读隔离级别下工作。
MVCC 两种读形式:
- 快照读:读取的只是当前事务的可见版本,不用加锁。而你只要记住 简单的 select 操作就是快照读(select * from table where id = xxx)。
- 当前读:读取的是当前版本,比如 特殊的读操作,更新/插入/删除操作
MVCC 使用了“三个隐藏字段”和可见性算法实现版本并发控制
- RowID:隐藏的自增ID,当建表没有指定主键,InnoDB会使用该RowID创建一个聚簇索引。
- DB_TRX_ID:最近修改(更新/删除/插入)该记录的事务ID。
- DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本。
MVCC可见性算法(https://www.jianshu.com/p/88dd4bcc3920)
undo Log:
事务的回滚日志,是可见性算法 的非常重要的部分,分为两类。- insert undo log:事务在插入新记录产生的undo log,当事务提交之后可以直接丢弃
- update undo log:事务在进行 update 或者 delete 的时候产生的 undo log,在快照读的时候还是需要的,所以不能直接删除,只有当系统没有比这个log更早的read-view了的时候才能删除。ps:所以长事务会产生很多老的视图导致undo log无法删除 大量占用存储空间。
read-view:
读视图,是MySQL秒级创建视图的必要条件,比如一个事务在进行 select 操作(快照读)的时候会创建一个 read-view ,这个read-view 其实只是三个字段。
alive_trx_list(我自己取的):read-view生成时刻系统中正在活跃的事务id。
up_limit_id:记录上面的 alive_trx_list 中的最小事务id。
low_limit_id:read-view生成时刻,目前已出现的事务ID的最大值 + 1。
可见性算法过程:
其实主要思路就是:当生成read-view的时候如何去拿获取的 DB_TRX_ID 去和 read-view 中的三个属性()去作比较。
- 首先比较这条记录的 DB_TRX_ID 是否是 小于 up_limit_id 或者 等于当前事务id。如果满足,那么说明当前事务能看到这条记录。如果大于则进入下一轮判断
- 然后判断这条记录的 DB_TRX_ID 是否 大于等于 low-limit-id。如果大于等于则说明此事务无法看见该条记录,不然就进入下一轮判断。
- 判断该条记录的 DB_TRX_ID 是否在活跃事务的数组中,如果在则说明这条记录还未提交对于当前操作的事务是不可见的,如果不在则说明已经提交,那么就是可见的。
MVCC是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。当然存储的并不是实际的时间值,而是系统版本号(system version number)。每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。
下面看一下在REPEATABLE READ隔离级别下,MVCC具体是如何操作的。
SELECT
InnoDB会根据以下两个条件检查每行记录:- InnoDB只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的。
- 行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除。
只有符合上述两个条件的记录,才能返回作为查询结果
INSERT
- InnoDB为新插入的每一行保存当前系统版本号作为行版本号。
DELETE
- InnoDB为删除的每一行保存当前系统版本号作为行删除标识。
UPDATE
- InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。
保存这两个额外系统版本号,使大多数读操作都可以不用加锁。这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。