zoukankan      html  css  js  c++  java
  • MySQL知识网络

    MySQL知识网络

    引擎

    • InnoDB

      1. 支持表锁 、行锁
      2. 支持事务
      3. *.frm 表结构文件
      4. *.idb 表数据和索引文件
    • MyISAM

      1. 支持表锁
      2. *.frm 表结构文件
      3. *.MYD 表数据文件
      4. *.MYI表索引文件
    • MEMORY

      内存表

    • CSV

      csv形式

    索引

    • BTREE

      1. 主键索引

        主键索引就是聚簇索引

      2. 聚簇索引

        聚簇索引就是主键索引

      3. 普通索引

        数据端也存在主键 (回表)

      4. 联合索引

        最左前缀原则

    • HASH

      1. key:value

    事务

    事务是一组操作的集合

    事务特性

    • 原子性:满足原子操作,对数据操作,要么全部成功,要么全部失败。

    • 一致性:数据开始和完成,数据都保持一致。

    • 隔离性:事物之间是相互独立的,中间状态对外不可见。

    • 持久性:数据的修改时永久的

    隔离级别

    1. 原因

    多个事务并发执行,会出现几个问题

    • 脏读:A事务未提交, B事务读到A的结果(破坏了隔离性)

    • 不可重复读:A事务在本次事务中,对自己未操作的数据,进行多次读取,出现了结果不一致,或者记录不存在的情况。(破坏了一致性, update)

      注:主要是MVCC、和锁来解决这个问题

    • 幻读:A事务在本次事务中,对自己的数据进行多次读取,第一次不存在, 第二次记录出现了。(破坏了一致性, insert)

      注:主要用next-key锁来解决这个问题

    2.解决办法(制定标准)

    为了权衡【隔离】和【并发】的矛盾,ISO定义了四个事务级别,每个级别的隔离程度不同,出现的情况也不同

    • Read uncommitted

      存在问题:脏读、不可重复读、幻读

      实现原理:读无锁

      改:启用行级共享锁

    • Read committed

      存在问题:不可重复读、幻读

      实现原理:读行级共享锁

      改:行级排他锁

    • Repeatable read

      存在问题:幻读

      实现原理: 读取共享锁直到事务结束释放 写排它锁直到事务结束释放

    • Serializable

      存在问题:不可并发

      实现原理:读取表级共享锁直到事务结束释放, 写表级排它锁直到事务结束释放

    3.实现(InnoDB)
    • 锁机制:阻止其他事物进行操作,各个隔离级别主要体现在读取数据是加的锁和释放的时机。

      RU: 事务读取时, 不加锁。

      RC: 事务读取时,加行级共享锁(读到才加锁), 一旦读完,立即释放(并不是事务结束)。

      RR: 事务读取时,加行级共享锁,直到事务结束才会释放。

      SE: 事务读取时加表级共享锁,直到事务结束时,才释放

    • MVCC机制:生成一个数据快照,并用这个快照来提供一定级别的一致性读取,也成为了多版本数据控制。(基于undo做的快照,将读取数据页变成读快照来防止脏读、幻读、不可重复去的问题)

    原理:

    1. 通过每行保存两个隐藏列:trx_id(事务id)和 roll_pointer(回滚指针)两个字段

    2. 每次操作都会生成一条undo log日志,回滚指针指向前一条数据

      • 从最新记录开始找:

        如果当前记录:事务id<未提交事务的最小id,则可读(即:活跃事务最小id)

        如果当前记录: 未提交事务的最小id <事务id <= 未提交事务的最大id,则判断是否存在未提交事务数组中,存在则不可读(当然自己的事务也是可读),不存在可读

        如果当前记录:事务id>未提交事务的最大id, 则不可读

    注:可重复读仅在事务开始创建一次快照,而读已提交是每次执行语句时都要重新创建一次。

    快照的规则:

    1. 事务内更新可读到
    2. 版本未提交,不能读到
    3. 版本已提交,但是在快照后创建的,不能读到
    4. 版本已提交,且在快照创建前创建的,可以读到

    并发写问题

    ​ 多个事务对同一条数据修改。更新前要先读数据,这里的说的读,是更新之前的读叫做“当前读”,总是当前版本的数据, 也就是多个版本中最新一次提交的那版。

    • 实际就是【CAS版本控制】和【读写分离】思想

    • 主要用于RC和RR级别

    分类

    MySQL锁分为共享锁排它锁, 也叫读锁写锁

    读锁是共享的,可以通过lock in share mode实现,这时候只能读不能写。

    写锁是排他的,它会阻塞其他的写锁和读锁。从颗粒度来区分,可以分为表锁行锁两种。

    表锁会锁定整张表并且阻塞其他用户对该表的所有读写操作,比如alter修改表结构的时候会锁表。

    行锁又可以分为乐观锁悲观锁,悲观锁可以通过for update实现,乐观锁则通过版本号实现。

    行锁&表锁

    只有明确锁定索引, 才会执行行锁,否则执行表锁

    • 无锁

      # 主键不存在
      select * from user where id=-1 for update;
      
    • 行锁

      select * from user where id=1 for update;
      select * from user wehre id=1 and name='xxx' for update;
      
    • 表锁

      # 主键不明确
      select * from user where name='xxx' for update;
      select * from user where id <> 3 for update;
      

    锁算法(机制)

    行锁算法

    Record Lock(普通行锁)

    • 键值存在条件范围内

    • 记录存在

    Gap Lock(间隙锁)

    • 对于键值不存在的条件范围内,叫做“间隙”(GAP).引擎就会对这个“间隙”加锁,这种机制就是Gap机制(InnoDB独有的)

    Next-Key Lock(行 & 间隙)

    • 在键值范围条件内,同时键值又不在条件范围内 (注: Next-Key 锁 用来解决RR中幻读)

      注: Next-Key 锁 用来解决RR中幻读

      # id 只有1-50
      select * from user id>49 for update;
      
    表锁算法

    意向锁(升级机制)

    • 当一个事务带着表锁去访问一个被加了行锁的资源,那么, 此时, 这个行锁就会升级成意向锁,将表锁住。

      # 事务A
      select * from user where id=10 for update;
      # 事务B (B表锁中的值包含 A行锁 id=10)
      select * from user where name ='xxx' for update;
      

    自增锁

    • 事务插入自增类型的列时,获取自增锁

      如果一个事务正在往表中插入自增记录,其他事物都必须等待

    实现

    共享锁 & 排它锁

    行锁和表锁是粒度的概念, 共享锁和它他锁使他们的具体实现

    共享锁(s)
    • 允许一个事务去读一行,阻止其他事物去获取该行的排它锁; 都能读,但是不能改
    排他锁(x):写锁
    • 允许持有排它锁的事务去读数据,阻止其他事物去获取该资源的共享锁和排它锁; 改的时候谁都不许操作

    • 不能获取任何锁,不代表不能读

    注意

    • 某个事务获取数据的排它锁,其他事务不能获取该数据的任何锁,并不代表其他事务不能无锁读取数据。

      • 无锁
      select ... from ...
      
      • 共享锁
      select ... lock in share mode
      

      MySQL8.0以上,for share 代替了lock in share mode,但是任然支持lock in share mode;但是 nowait、skip locked,配合自旋锁,可以高效的实现一个等待队列。

      • 排它锁
      update ...
      delete ...
      insert ...
      select ... for update
      
      乐观锁&悲观锁

      无论是什么锁都需要加失败重试

      • 乐观锁

        概念:总是假设最好的情况,每次拿数据的时候都认为别人不会修改,所以不会上锁。但是在更新的时候判断一下在此期间别人有没有更新这个数据,一般通过版本号机制和CAS算法实现。乐观锁适用于写比较少的情况下(多读场景)

        一般通过版本号进行更新, 同版本方可更新成功,不同版本则需要重试更新操作,直到成功

        update user set name='xxx' where id=1 and version=1;
        
      • 悲观锁

        概念:总是假设最坏的情况,每次拿数据的时候都认为有人回修改,每次拿数据的时候都会上锁,然后别人想拿数据就一直堵塞。多写场景

        排它锁的实现

    日志

    InnoDB日志

    redo log (重做日志)

    redo log通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。

    作用:

    确保事务的持久性。防止在发生故障的时间点,当有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。

    undo log (回滚日志)

    undo用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录。

    作用:

    保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读

    MySQL server 日志

    bin log(归档日志)

    作用:

    用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。
    用于数据库的基于时间点的还原。

    redo log 和 binlog 区别

    • redo log是属于innoDB层面,binlog属于MySQL Server层面的,这样在数据库用别的存储引擎时可以达到一致性的要求。
    • redo log是物理日志,记录该数据页更新的内容;binlog是逻辑日志,记录的是这个更新语句的原始逻辑
    • redo log是循环写,日志空间大小固定;binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖。
    • binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。

    一条更新语句执行的顺序

    update T set c=c+1 where ID=2;

    • 执行器先找引擎取 ID=2 这一行。ID 是主键,引擎直接用树搜索找到这一行。如果 ID=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
    • 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。
    • 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。
    • 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
    • 执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成。

    SQL优化

    常见面试题

    1. mysql主从同步怎么搞的?分哪几个过程?如果有一台新机器要加到从机里,怎么个过程。
    1. 主mysql将日志写入bin log
    2. 从mysql连上主mysql,获取bin log
    3. 主mysql dump线程将bin log日志推送给从mysql
    4. 从mysql将得到的日志 写入relay log
    5. 从mysql开一个sql线程 读取relay log 并执行sql语句,完成同步
    6. 从mysql记录自己的bin log
    1. binlog 日志是 master 推的还是 salve 来拉的?

    刚刚连接的时候是 slave来拉 后面是master主动推过来

    binlog 有哪几种模式

    row 记录数据值,同时也会记录关联表的信息情况,优点不冲突 缺点日志大

    statement 记录sql逻辑, 优点数据小, 缺点使用function 可能导致主从数据不一致

    mixed row和statement的结合

    mysql有哪些日志

    redo log、bin log、undo log、relay log、slow query log、error log、general log

    mysql加锁规则

    加锁规则 next-key lock

    • 唯一索引等值查询
    1. 记录存在时,next-key lock 退化成 行锁
    2. 记录不存在时, next-key lock 退化成 间隙锁
    • 非唯一索引等值查询
    1. 记录存在时,加next-key lock外, 还额外加一个 间隙所, 也就是两把锁
    2. 当记录不存在时,加next-key lock, next-key lock退化成 间隙锁
    此时此刻,非我莫属
  • 相关阅读:
    Hibernate逍遥游记-第10章 映射继承关系-001继承关系树中的每个具体类对应一个表
    Hibernate逍遥游记-第9章 Hibernate的映射类型
    Hibernate逍遥游记-第8章 映射组成关系(<component>、<parent>)
    Hibernate逍遥游记-第7章 Hibernate的检索策略和检索方式(<set lazy="false" fetch="join">、left join fetch、FetchMode.JOIN、)
    Hibernate逍遥游记-第6章 通过Hibernate操纵对象(select-before-update)
    Hibernate逍遥游记-第5章映射一对多-02双向(<set>、<key>、<one-to-many>、inverse、cascade="all-delete-orphan")
    Hibernate逍遥游记-第5章映射一对多-01单向<many-to-one>、cascade="save-update"、lazy、TransientObjectException
    Hibernate逍遥游记-第4章映射对象标识符-increment、identity、hilo、native、assigned、sequence、<meta>
    Hibernate逍遥游记-第3章对象-关系映射基础-access="field"、dynamic-insert、dynamic-update、formula、update=false
    CentOS 6.5安装Apache
  • 原文地址:https://www.cnblogs.com/taozhengquan/p/15017878.html
Copyright © 2011-2022 走看看