zoukankan      html  css  js  c++  java
  • mysql_5_2 INNODB 核心特性

    mysql_5_2 INNODB 核心特性

    标签(空格分隔): mysql


    什么是事务?

    事务是伴随着 《交易类》的业务场景出现的工作机制
    保证交易的“和谐“
    
    计算机中
        A 转账 B
    开启事务
    A 账户 100元 : A-100元         update A - 100
    B 账户 0元: B+100元            update B + 100
    事务结束
    

    事务的ACID标准特性

    原子   atomicity
        原子是物质的最小构成单元,具有不可再分的特性。
        在一个事务工作单元中,所有标准事务语句DML 要么全成功,要么没发生
    一致   consistency
        事物发生前,中、后都应该保证数据的一致状态。
        mysql的各项功能的设计,都是要最终保证一致性。
    隔离   isolation
        mysql可以支持多事务并发工作的系统。
        A工作的时候,不能够受到其他事务的影响。
    持久   durability
        事务提交后,此次事务操作的所有数据,都要永久保存下去。
        不会因为数据实例发生故障,导致数据失效。
    

    如何开启事务

    开启事务 
    begin/start transaction
    
    commit   提交事务      
    
    rollback 回滚事务
    

    哪些dml语句可以使用事务

    INSERT
    DELETE
    UPADTE
    SELECT   没什么作用
    

    事务的自动提交

    自动提交  autocommit     默认开启
    select @@autocommit
    show variables like "autocommit";
    
    如果是交易类的业务
    方案1:
        autocommit=0 ; commit,手动提交才生效
    方法2:
        autocommit=1
        每次想要发生事务性操作
        begin和commit都手动操作
    1.临时生效
        set global autocommit=0;
    重启开启会话生效
    永久生效
    vim /etc/my.cnf
    autocommit=0
    重启数据库生效。
    

    什么时候自动提交事务

    使用dml语句时 会自动在这个dml之前加一个begin;之后加一个commit
    

    隐式提交

    设置了autocommit=1
    定义一些DDL、DCL非DML语句时操作   
    创建表    
    修改列属性    
    他就会隐式提交这些事务。
    
    session 1
    begin;
    DML1
    DML2
    COMMIT;
    DROP DATABASE WORLD
    

    什么时候隐式提交

    DDL语句 ALTER CREATE DROP
    DCL语句 GRANT REVOKE SETPASSWORD
    锁定语句 LOCK TABLES 和 UNLOCK TABLES
    隐式提交的语句实例:
    TRUNCATE TABLE
    LOAD DATA INFILE
    SELECT FOR UPDATE
    

    隐式回滚

    会话关闭
    数据库宕机
    事务语句执行失败
    

    analyze table

    统计数据            
    查询优化器
    

    保存点 save point

    修改3次
    
    可以在第二次保存 
    begin
    sql语句
    save point s1
    sql语句
    save point s2
    sql语句
    save point s3
    
    可以rollback 点
    

    回滚就只会回一次

    INNODB事务的ACID如何保证?

    重做日志

    redo log 重做日志 ib_logfile0-N 48M 轮训使用
    记录的是数据页的变化
    redo log buffer redo内存区域
    

    数据页存储位置

    ibd   存储数据行和索引
    buffer pool 缓冲区池,数据页和索引页的缓冲
    

    LSN 日志序列号

    自盘数据页 redo文件 buffer pool redo buffer
    mysql 每次数据库启动,都会比较磁盘数据页和redolog的LSN,必须要求两者LSN一致数据库才能正常启动
    WAL write ahead log 日志优先写的方式实现持久化
    脏页:内存脏页,内存中发生了修改,没写入到磁盘之前,我们把内存页趁之为脏页
    CKPT:checkpoint 检查点,就是讲脏页刷写到磁盘的动作
    TXID:事务号,INNODB会为每一个事务生成一个事务号,伴随着整个事务。
    UNDO:IBDATA1 存储了事务工作过程中的回滚信息。
    

    redo作用

    重做日志,事务日志的一种。
    在事务ACID过程中,实现的是D持久化的作用,对于AC也有相应的作用
    

    redo日志位置

    iblogfile0
    iblogfile1
    

    redo buffer

    redo buffer
    LSN
    

    commit;
    刷新当前事务的redo buffer到磁盘
    还会顺便将一部分redo buffer中没有提交的事务日志刷新到磁盘

    redo存储的是事务工作过程中,数据页变化,commit时会立即写入磁盘 默认.日志落盘成功commit。

    正常mysql工作流程当中
    主要的工作是提供快速持久化功能。
    当mysql出现crash异常宕机时,
    主要提供的是前滚功能(CSR).

    innodb_flush_log_at_trx_commit = 0 / 1 / 2
    1:每次事务提交时,会立即刷新redo到磁盘,commit才能成功
    0:每秒刷新日志redo buffer到os cache 在fsync到磁盘 异常宕机时,可能会丢失一秒内的数据。
    2.每次事务提交,都立即刷新redo buffer 到 os cache 在每秒fsync() 磁盘,异常宕机时,会有可能导致丢失1s内的事务。

    默认是1

    redo buffer 还跟操作系统缓存机制有关,所以刷写策略可能和innodb_flush_method参数有一定关系。
    redo 也有 group commit 可以理解为 在每次刷新已提交的redo时,顺便可以将一些未提交的事务redo页一次性刷写到磁盘。此时为了区分不同装填的redo,会加一些比较特殊的标记(是否提交标记)

    undo logs

    undo 回滚日志
    

    作用

    在事务ACID过程中,实现的是“A”原子性的作用
    另外CI也依赖于undo
    在rollback是,将数据恢复到修改之前的状态
    在CSR实现的是,将redo当中几率的未提交的时候进行回滚。
    undo提供了快照技术,保存事务修改之前的数据状态,保证MVCC,隔离性,mysqldump的热备恢复机制。
    
    
    undo在生成过程中也会记录redo信息。
    
    
    宕机使用redo前滚 再使用undo进行回滚 重新恢复内存中的信息 。
    

    什么是一致性快照

    每个事物开启时,都会通过undo日志获取一个一致性的快照。
    undo提供快照技术,保存事务修改之前的数据状态
    

    隔离级别和锁机制

    主要是提供I的特性,另外对于C的特性也有保证。
    

    隔离性设置

    set session transaction isolation level READ COMMITTED
    set global transaction_isolation="read-uncommitted"
    vim /etc/my.cnf
    transaction_isolation="read-uncommitted"
    重启生效

    读 未提交 RU

    问题 脏读  不可重复读 幻读
    

    读 已提交 RC

    问题 幻读 不可重复读
    

    可重复读 RR

    一个事物第一次读过某条记录后,即使其他事务修改了记录的值提交,该事务之后在读这条记录时,读到的仍然是第一次读到的值,而不是每次都读到不同的数据,这就是可重复读
    
    解决了不可重复,但会出现幻读。
    
    mysql  隔离级别在可重复读 () 的标准    但是 还是存在 幻读 的问题
    
    MVCC重要功能
    防止不可重复读现象。
    利用了undo的一致性快照
    
    幻读
    
    通过RR,已经可以解决99以上的幻读。为了更加严谨,加入了GAP间隙锁,next-lock
    
    间隙锁 锁定 范围内的所有记录 解决幻读
    

    串行化 SR

    同一时刻只能够执行 读或写的操作。
    不会出现任何问题
    

    脏读

    任何一个事务修改   其他事务就能够读取新的数据         就是脏读
    

    不可重复读

    一个事务读取上一秒还是老数据,下一秒等其他事务提交后。第一个事务读取发现数据就变了。
    

    幻读

    select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。
    亦或是 更新 时 别人提交了 但是发现自己更新的数据 多了一条没有更新的(别人提交的数据) 
    

    并发读

    transaction_id 事务id 最近修改这条数据的事务id
    roll_pointer 回滚节点

    例子

    环境是
    读已提交

    0->1(80)->2(200)

    200事务 会不管现在的数据,然后根据transaction_id去找自己修改的事务id的数据 roll_pointer指向了版本连的数据。

    A(100) b(200)

    A读数据 会发现没有id是自己的
    就会创建readView
    创建m_ids:[81,82,200,300]
    在m_ids 寻找已提交的事务 80 在取数据。

    如何这时候b 事务 提交了

    a的readview 就会变化
    m_ids:[81,82,300]

    直接取200 这个已提交的事务即可

    未修改的地方存放在undolog里面。

    m_ids 提交完成的会在前面。

    ReadView 实现了 MVCC 多版本并发控制 完成了 读已提交 和 可重复读 隔离级别。

    环境是
    可重复读

    A B
    1 1-2
    COMMIT;
    还是1

    还是基于readview

    A去查
    生成
    readview
    m_ids:[81,82,200,300];

    b commit;

    如何这时候b 事务 提交了

    a的readview 在可重复读的环境下,不会变化, 而是直接用上次生成好的。
    m_ids:[81,82,200,300]


    mysql 锁机制

    介绍

    相当于厕所的门
    

    作用

    保证事务的隔离性。也保证了数据的一致性
    保证资源不被同时争用。锁是属于资源的,不是某个事物的特性。
    每次事务需要资源的时候,需要申请持有资源的锁
    

    锁类型

    资源:

    内存锁:
        mutex latch
    
    文件锁 对象锁:
    
        MDL(元数据锁)  修改元数据时 DDL  --> alter
        table_lock       表锁 DDL  备份(FTWRL全局表锁) lock tables t1 read 也可以升级为表锁
        record(row) lock 行锁 索引锁 锁定聚簇索引
        GAP              间隙锁 RR级别 非唯一索引 普通辅助索引间隙锁
        Next_lock        下一键锁 GAP+RECORD LOCK 普通辅助索引范围锁     update 一个范围 这个范围再插入 就会爆锁等待
        
        更新表里面的30% 开始走全表 这时候会锁住表
    

    粒度:

    MDL(元数据锁)   粒度最高 都锁住了
    table_lock        表都锁柱了
    record(row) lock  可以锁多行或一行
    GAP               可以锁多行或一行
    Next_lock         可以锁多行或一行
    

    功能锁:

    IS : 意向共享锁    表级别
    S  : 共享锁 读锁   行级别
    IX : 意向排它锁    表级别
    X  : 排它锁 写锁   行级别
    
    排他锁 不允许他人在进行修改
    

    功能锁冲突表:

            X锁          IX锁         S锁        IS锁
    	
    X锁     冲突        冲突          冲突       冲突
    
    IX锁    冲突        不冲突        冲突       不冲突
    
    S锁     冲突        冲突        不冲突       不冲突
    
    IS锁    冲突        不冲突      不冲突       不冲突
    

    冲突 就会出现锁等待

    表加锁与解锁

    lock tables t1 read;           加上s锁
    unlock tables t1;
    
    lock tables t1 write;           加上x锁
    unlock tables t1;
    
    
    select ... lock in share mode 加上 is 锁
    
    select ... for update         加上 ix 锁
    

    查看锁等待的情况

    select * from sys.innodb_lock_waits 
    

    事物ACID的保证

    A : 原子性      UNDO REDO LOG 来保证
    D : 持久性      commit的数据性  redo(WAL)记录保证 
    I : 隔离性      ISOLATION LEVEL  数据隔离级别    LOCK   锁  MVCC  (UNDO 日志) 技术
    C :一致性      保证工作前、中、后。数据的状态都是完整的
                    C的特性是以上共同保证的特性。
                    写一致性
                        undo redo lock
                    读一致性
                         ISOLATION LEVEL  数据隔离级别    MVCC(UNDO 日志)技术
                    
                    数据页的一致性
                    double write buffer 磁盘区域
                    内存写入磁盘 会先在redo log 里面保存doblewrite 顺序读写 让后在写入数据。放置宕机,写入失败。
    

    存储引擎核心参数

    双一标准之一: redo log 刷写参数
    innodb_flush_log_at_trx_commit=1/0/2

    1:每次事务提交时,会立即刷新redo到磁盘,commit才能成功
    0:每秒刷新日志redo buffer到os cache 在fsync到磁盘 异常宕机时,可能会丢失一秒内的数据。
    2.每次事务提交,都立即刷新redo buffer 到 os cache 在每秒fsync() 磁盘,异常宕机时,会有可能导致丢失1s内的事务。

    innodb_flush_method=fsync/O_DIRECT/O_DIRECT/O_SYNC
    作用 : 控制mysql 刷写磁盘时 是否需要使用os_cache
    OOM ------> innodb_buffer_pool_size = 80% total

    fsync 参数 默认
    buffer pool 的数据写磁盘的时候 需要经历os_cache 再写入磁盘
    redo buffer 的数据写磁盘的时候 需要经历os_cache 再写入磁盘

    o_sync:
    buffer pool 的数据写磁盘的时候 需要经历os_cache 再写入磁盘
    redo buffer 的数据写磁盘的时候 不经历os_cache 写入磁盘

    O_DIRECT:
    buffer pool 的数据写磁盘的时候 不经历os_cache 写入磁盘
    redo buffer 的数据写磁盘的时候 需要经历os_cache 再写入磁盘

    建议是用o_direct,最好配合固态盘

    innodb_buffer_pool_size

    作用:数据缓冲区的总大小。缓冲数据页和索引页。是mysql最大的内存区域。
    70% 左右

    查看innodb状态

    show engine innodb status

    并发写

    读锁 共享锁 S锁 只能读了 不能写

    写锁 排它锁

    select 不加锁 同时也无视锁

        X锁         S锁
    

    X锁 冲突 冲突

    S锁 冲突 不冲突

    select .. lock in share mode

    加读锁

    select for update

    加写锁
    delete
    insert
    update
    都是写锁
    

    行锁

    LOCK_REC_NOT_GAP 单个行记录上的锁
    LOCK_GAP 间隙锁 锁定一个范围 但不包括纪律本身 gap锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。
    LOCK_ORDINARY 锁定一个范围 并且锁定记录本身,对于行的查询 都是采用这个方法,主要目的解决幻读

    Read commited 读已提交

    隔离级别 锁的情况

    主键使用 for update 上锁 只会锁住那一行
    唯一索引同样
    普通索引一样

    select * from t1 where c = '1' for update;
    符合的加锁 不符合的数据不会加锁

    主键使用 for update 上锁 锁住了一行 可以isnert 操作全表 会出现幻读情况

    上锁需要考虑间隙 加锁也是对间隙而言的 没在间隙内的 可以做写操作的

    repeat commited 重复度

    主键使用 for update 上锁 只会锁住那一行

    主键使用 for update 上锁 锁住了一行 无法isnert 操作全表 B+树 无法插入 无法排序将数据放入叶子节点中。 防止了幻读

    上锁需要考虑间隙 加锁也是对间隙而言的 没在间隙内的 可以做写操作的

    不使用索引 mysql就会索引全部范围 不运行insert 为了解决幻读。

    表锁
    lock table f1 read
    lock table f1 write

    select readview

    update 加锁

    表锁
    如果有行锁
    lock is锁
    lock ix锁

  • 相关阅读:
    poi 导出Excel
    【EasyUI】combotree和combobox模糊查询
    多线程和Socket套接字
    io流
    前端页面的语法 jquery javascript ajax
    spring+mybatis
    Exchanger 原理
    CountDownLatch、CyclicBarrier和 Semaphore
    sleep() 、join()、yield()有什么区别
    创建线程的方式及实现
  • 原文地址:https://www.cnblogs.com/hywhyme/p/14564362.html
Copyright © 2011-2022 走看看