日志

mysql服务器日志

mysql01

  • 错误日志:-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为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。

保存这两个额外系统版本号,使大多数读操作都可以不用加锁。这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。