zoukankan      html  css  js  c++  java
  • mysql事务隔离级别

    1. 什么是事务?

    理解什么是事务最经典的就是转账的栗子,相信大家也都了解,这里就不再说一边了.

    事务是一系列的操作,他们要符合ACID特性.最常见的理解就是:事务中的操作要么全部成功,要么全部失败.但是只是这样还不够的.

    2. ACID是什么?可以详细说一下吗?

    A=Atomicity

    原子性,就是上面说的,要么全部成功,要么全部失败.不可能只执行一部分操作.

    C=Consistency

    系统(数据库)总是从一个一致性的状态转移到另一个一致性的状态,不会存在中间状态.

    I=Isolation

    隔离性: 通常来说:一个事务在完全提交之前,对其他事务是不可见的.注意前面的通常来说加了红色,意味着有例外情况.

    D=Durability

    持久性,一旦事务提交,那么就永远是这样子了,哪怕系统崩溃也不会影响到这个事务的结果.

    3. 同时有多个事务在进行会怎么样呢?

    多事务的并发进行一般会造成以下几个问题:

    • 脏读: A事务读取到了B事务未提交的内容,而B事务后面进行了回滚.

    • 不可重复读: 当设置A事务只能读取B事务已经提交的部分,会造成在A事务内的两次查询,结果竟然不一样,因为在此期间B事务进行了提交操作.

    • 幻读: A事务读取了一个范围的内容,而同时B事务在此期间插入了一条数据.造成"幻觉".

    4. 怎么解决这些问题呢?MySQL的事务隔离级别了解吗?

    MySQL的四种隔离级别如下:

    • 未提交读(READ UNCOMMITTED)

    这就是上面所说的例外情况了,这个隔离级别下,其他事务可以看到本事务没有提交的部分修改.因此会造成脏读的问题(读取到了其他事务未提交的部分,而之后该事务进行了回滚).

    这个级别的性能没有足够大的优势,但是又有很多的问题,因此很少使用.

    • 已提交读(READ COMMITTED)

    其他事务只能读取到本事务已经提交的部分.这个隔离级别有 不可重复读的问题,在同一个事务内的两次读取,拿到的结果竟然不一样,因为另外一个事务对数据进行了修改.

    • REPEATABLE READ(可重复读)

    可重复读隔离级别解决了上面不可重复读的问题(看名字也知道),但是仍然有一个新问题,就是幻读

    当你读取id> 10 的数据行时,对涉及到的所有行加上了读锁,此时例外一个事务新插入了一条id=11的数据,因为是新插入的,所以不会触发上面的锁的排斥

    那么进行本事务进行下一次的查询时会发现有一条id=11的数据,而上次的查询操作并没有获取到,再进行插入就会有主键冲突的问题.

    • SERIALIZABLE(可串行化)

    这是最高的隔离级别,可以解决上面提到的所有问题,因为他强制将所以的操作串行执行,这会导致并发性能极速下降,因此也不是很常用.

    5. Innodb使用的是哪种隔离级别呢?

    InnoDB默认使用的是可重复读隔离级别.

    可通过 select @@tx_isolation  查看

    6. 对MySQL的锁了解吗?

    当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制.

    就像酒店的房间,如果大家随意进出,就会出现多人抢夺同一个房间的情况,而在房间上装上锁,申请到钥匙的人才可以入住并且将房间锁起来,其他人只有等他使用完毕才可以再次使用.

    7. MySQL都有哪些锁呢?像上面那样子进行锁定岂不是有点阻碍并发效率了?

    从锁的类别上来讲,有共享锁和排他锁.

    共享锁: 又叫做读锁. 当用户要进行数据的读取时,对数据加上共享锁.共享锁可以同时加上多个.

    排他锁: 又叫做写锁. 当用户要进行数据的写入时,对数据加上排他锁.排他锁只可以加一个,他和其他的排他锁,共享锁都相斥.

    用上面的例子来说就是用户的行为有两种,一种是来看房,多个用户一起看房是可以接受的. 一种是真正的入住一晚,在这期间,无论是想入住的还是想看房的都不可以.

    锁的粒度取决于具体的存储引擎,InnoDB实现了行级锁,页级锁,表级锁.

    他们的加锁开销从大大小,并发能力也是从大到小.

    存储引擎相关

    1. MySQL支持哪些存储引擎?

    MySQL支持多种存储引擎,比如InnoDB,MyISAM,Memory,Archive等等.

    在大多数的情况下,直接选择使用InnoDB引擎都是最合适的,InnoDB也是MySQL的默认存储引擎.

    1. InnoDB和MyISAM有什么区别?

    • InnoDB支持事物,而MyISAM不支持事物

    • InnoDB支持行级锁,而MyISAM支持表级锁

    • InnoDB支持MVCC, 而MyISAM不支持

    • InnoDB支持外键,而MyISAM不支持 

    • InnoDB不支持全文索引,而MyISAM支持

    MySQL的binlog有有几种录入格式?分别有什么区别?

    有三种格式,statement,row和mixed.

    • statement模式下,记录单元为语句.即每一个sql造成的影响会记录.由于sql的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一些使用了函数之类的语句无法被记录复制.

    • row级别下,记录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致大量行的改动(比如alter table),因此这种模式的文件保存的信息太多,日志量太大.

    • mixed. 一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row.

    此外,新版的MySQL中对row级别也做了一些优化,当表结构发生变化的时候,会记录语句而不是逐行记录.

    4. 超大分页怎么处理?

    超大的分页一般从两个方向上来解决.

    • 数据库层面,这也是我们主要集中关注的(虽然收效没那么大)

      类似于select * from table where age > 20 limit 1000000,10这种查询其实也是有可以优化的余地的.

      这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢.

      我们可以修改为select * from table where id in (select id from table where age > 20 limit 1000000,10)

      这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快.

      同时如果ID连续的好,我们还可以select * from table where id > 1000000 limit 10,效率也是不错的

      优化的可能性有许多种,但是核心思想都一样,就是减少load的数据.

    • 从需求的角度减少这种请求….主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击.

    解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可. 

    5. 关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?

    在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们.

    慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?

    所以优化也是针对这三个方向来的,

    • 首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写.

    • 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引.

    • 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表.

    6. 上面提到横向分表和纵向分表,可以分别举一个适合他们的例子吗?

    横向分表是按行分表.假设我们有一张用户表,主键是自增ID且同时是用户的ID.数据量较大,有1亿多条,那么此时放在一张表里的查询效果就不太理想.

    我们可以根据主键ID进行分表,无论是按尾号分,或者按ID的区间分都是可以的. 

    假设按照尾号0-99分为100个表,那么每张表中的数据就仅有100w.这时的查询效率无疑是可以满足要求的.

    纵向分表是按列分表.假设我们现在有一张文章表.包含字段id-摘要-内容.而系统中的展示形式是刷新出一个列表,列表中仅包含标题和摘要

    当用户点击某篇文章进入详情时才需要正文内容.此时,如果数据量大,将内容这个很大且不经常使用的列放在一起会拖慢原表的查询速度.

    我们可以将上面的表分为两张.id-摘要,id-内容.当用户点击详情,那主键再来取一次内容即可.而增加的存储量只是很小的主键字段.代价很小.

    当然,分表其实和业务的关联度很高,在分表之前一定要做好调研以及benchmark.不要按照自己的猜想盲目操作.

    7. 什么是存储过程?有哪些优缺点?

    存储过程是一些预编译的SQL语句。

    1、更加直白的理解:存储过程可以说是一个记录集,它是由一些T-SQL语句组成的代码块

    这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。

    2、存储过程是一个预编译的代码块,执行效率比较高,一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率,可以一定程度上确保数据安全

    但是,在互联网项目中,其实是不太推荐存储过程的,比较出名的就是阿里的《Java开发手册》中禁止使用存储过程

    我个人的理解是,在互联网项目中,迭代太快,项目的生命周期也比较短,人员流动相比于传统的项目也更加频繁

    在这样的情况下,存储过程的管理确实是没有那么方便,同时,复用性也没有写在服务层那么好.

    8. 说一说三个范式

    第一范式: 每个列都不可以再拆分.

    第二范式: 非主键列完全依赖于主键,而不能是依赖于主键的一部分. 

    第三范式: 非主键列只依赖于主键,不依赖于其他非主键.

    在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由.比如性能. 事实上我们经常会为了性能而妥协数据库的设计.

    9. MyBatis 中的 #

    乱入了一个奇怪的问题…..我只是想单独记录一下这个问题,因为出现频率太高了.

    # 会将传入的内容当做字符串,而$会直接将传入值拼接在sql语句中.

    所以#可以在一定程度上预防sql注入攻击.

    参考链接

    https://mp.weixin.qq.com/s?__biz=MzU0OTk3ODQ3Ng==&mid=2247486376&idx=1&sn=479722e712e3a0ed16b08c7e815548bf&chksm=fba6e3abccd16abd8502955ec6b4157215eba220fc66046fb5e3331cb5322a6fd924b29672f5&scene=0&xtrack=1&key=68be3ae943e49b4fee5da1bae77fc0f4395ca9f0317f6c9594773dc21c4bd8d194f682cb3579563d38081608a44c88d050f72f5980014fbde1b019fedd39e71f276139d876800c87ff32a328475bf6ba&ascene=1&uin=NDAyNDg1OTc1&devicetype=Windows+7&version=62060833&lang=zh_CN&pass_ticket=Xac0t7G6Fn6Ff8xKOv%2BZV3MOlalheTY8teSHqzlpyuLWSfzCRGqevP4wG0RM8DRX

    人生在勤,不索何获,坚持自有收获
  • 相关阅读:
    Sql学习第二天——SQL DML与CTE解释
    Sql学习第一天——SQL UNION 和 UNION ALL 操作符(1)
    Sql学习第一天——SQL 练习题(3)
    Sql学习第一天——SQL 将变量定义为Table类型(2)
    C#性能优化实践(摘抄)
    SQL数据纵横列查询
    「SHOI2006」有色图
    SP419/422 TRANSP(2) Transposing is Fun
    ARC084F XorShift
    洛谷 P4708 画画(无标号欧拉子图计数)
  • 原文地址:https://www.cnblogs.com/quyf/p/11770163.html
Copyright © 2011-2022 走看看