zoukankan      html  css  js  c++  java
  • 互联网项目中mysql推荐(读已提交RC)的事务隔离级别

    【原创】互联网项目中mysql应该选什么事务隔离级别

    Mysql为什么不和Oracle一样使用RC,而用RR

    使用RC的原因

    这个是有历史原因的,当然要从我们的主从复制开始讲起了!
    主从复制,是基于什么复制的?
    是基于binlog复制的!这里不想去搬binlog的概念了,就简单理解为binlog是一个记录数据库更改的文件吧~

    binlog有几种格式?
    OK,三种,分别是

    statement:记录的是修改SQL语句
    row:记录的是每行实际数据的变更
    mixed:statement和row模式的混合

    Mysql在5.0这个版本以前,binlog只支持STATEMENT这种格式!而这种格式在读已提交(Read Commited)这个隔离级别下主从复制是有bug的,因此Mysql将可重复读(Repeatable Read)作为默认的隔离级别!
    接下来,就要说说当binlog为STATEMENT格式,且隔离级别为读已提交(Read Commited)时,有什么bug呢?如下图所示,在主(master)上执行如下事务

    此时在主(master)上执行下列语句

    select * from test;

    输出如下

    +---+
    | b |
    +---+
    | 3 |
    +---+
    1 row in set

    但是,你在此时在从(slave)上执行该语句,得出输出如下

    Empty set

    这样,你就出现了主从不一致性的问题!原因其实很简单,就是在master上执行的顺序为先删后插!而此时binlog为STATEMENT格式,它记录的顺序为先插后删!从(slave)同步的是binglog,因此从机执行的顺序和主机不一致!就会出现主从不一致!

    Mysql5.0前 slave与master执行顺序不一致解决方案

    (1) 隔离级别设为可重复读(Repeatable Read),在该隔离级别下引入间隙锁。当Session 1执行delete语句时,会锁住间隙。那么,Ssession 2执行插入语句就会阻塞住!
    (2) 将binglog的格式修改为row格式,此时是基于行的复制,自然就不会出现sql执行顺序不一样的问题!奈何这个格式在mysql5.1版本开始才引入。

    因此由于历史原因,mysql将默认的隔离级别设为可重复读(Repeatable Read),保证主从复制不出问题!

    互联网项目推荐将隔离级别设为读已提交(Read Commited)的原因

    对比RR级别。

    测试表结构如下:

    CREATE TABLE `test` (
    `id` int(11) NOT NULL,
    `color` varchar(20) NOT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB

    数据如下:

    +----+-------+
    | id | color |
    +----+-------+
    |  1 |  red  |
    |  2 | white |
    |  5 |  red  |
    |  7 | white |
    +----+-------+

    在RR隔离级别下,存在间隙锁,导致出现死锁的几率比RC大的多

    此时执行语句:

    select * from test where id <3 for update;

    在RR隔离级别下,存在间隙锁,可以锁住(2,5)这个间隙,防止其他事务插入数据!
    而在RC隔离级别下,不存在间隙锁,其他事务是可以插入数据!

    ps:在RC隔离级别下并不是不会出现死锁,只是出现几率比RR低而已!

    在RR隔离级别下,条件列未命中索引会锁表!而在RC隔离级别下,只锁行(***)

    此时执行语句:

    update test set color = 'blue' where color = 'white'; 

    在RC隔离级别下,其先走聚簇索引,进行全部扫描。加锁如下:

    但在实际中,MySQL做了优化,在MySQL Server过滤条件,发现不满足后,会调用unlock_row方法,把不满足条件的记录放锁。
    实际加锁如下:

    然而,在RR隔离级别下,走聚簇索引,进行全部扫描,最后会将整个表锁上,如下所示:

    ps:锁表其实是锁行+Gap锁

    在RC隔离级别下,半一致性读(semi-consistent)特性增加了update操作的并发性

    在5.1.15的时候,innodb引入了一个概念叫做“semi-consistent”,减少了更新同一行记录时的冲突,减少锁等待。
    所谓半一致性读就是,一个update语句,如果读到一行已经加锁的记录,此时InnoDB返回记录最近提交的版本,由MySQL上层判断此版本是否满足update的where条件。若满足(需要更新),则MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)!

    具体表现如下:
    此时有两个Session,Session1和Session2!
    Session1执行

    update test set color = 'blue' where color = 'red'; 

    先不Commit事务!
    与此同时Ssession2执行

    update test set color = 'blue' where color = 'white'; 

    session 2尝试加锁的时候,发现行上已经存在锁,InnoDB会开启semi-consistent read,返回最新的committed版本(1,red),(2,white),(5,red),(7,white)。MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)!
    而在RR隔离级别下,Session2只能等待!

    RC下的binlog格式(仅记录)

    该隔离级别下,用的binlog为row格式,是基于行的复制!Innodb的创始人也是建议binlog使用该格式!当然RR也是。

  • 相关阅读:
    iOS酷炫动画效果合集
    重载hash与isEqual:方法
    NSObject的hash方法
    带辉光效果的跑马灯
    线性重复动画
    TextKit简单示例
    计算一行文本的高度
    点击cell动态修改高度动画
    FastDFS图片服务器(分布式文件系统)学习。
    Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'jdbc.username' in string value "${jdbc.username}"
  • 原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/11323248.html
Copyright © 2011-2022 走看看