前言
从今天开始,更新一些mysql的基础知识,面试会遇到的知识点之类的内容。比如四个隔离级别,mvcc机制,三大日志,索引,B+树的形成等等,从数据库的底层来剖析索引和树是怎么形成的,以及查询缓存这些内容。
各位看官如果有想要了解的某些知识点,无论是mysql还是其他,都可以留言,会尽量及时回复的。
基础
三大范式
1、保持每列数据的原子性,比如客户信息表就是只有客户信息,不能存储订单信息
2、确保表中每列都和主键相关:一行数据只做一件事,如果数据有重复,就要拆分开来,比如客房信息表中有客户,那么一个客户可以定多个房间,这样客户信息就重复了。
3、每一列数据都应该和主键直接相关:比如一张表中有人员名单还有单位信息,那么这就是
人员id–人员信息–单位信息,应该把单位信息拆分出来
事务特性
ACID
A 原子性:Atomic在一个事务中,一堆sql,要么一起成功,要么一起失败,不存在某些成功某些失败的问题
C一致性:Consistency对于数据来说,一个事务执行完成之后,事务中所变更的数据都是要一致的,不能存在事务提交之后数据没有变更这种情况。
I 隔离性:Isolation各个事务之间不应该穿插执行,每个事务有自己独立执行的时间。
D持久性:Durability数据修改之后是永久存在的
四个隔离级别
读未提交
Read Uncommitted:这个很坑爹,就是说某个事务还没提交的时候,修改的数据,就让别的事务给读到了,这就恶心了,很容易导致出错的。这个也叫做脏读。
读已提交
Read Committed(不可重复读):这个比上面那个稍微好一点,但是一样比较尴尬,就是说事务A在跑的时候, 先查询了一个数据是值1,然后过了段时间,事务B把那个数据给修改了一下还提交了,此时事务A再次查询这个数据就成了值2了,这是读了人家事务提交的数据啊,所以是读已提交。这个也叫做不可重复读,就是所谓的一个事务内对一个数据两次读,可能会读到不一样的值。
可重复读
Read Repeatable:这个就是比上面那个再好点儿,就是说事务A在执行过程中,对某个数据的值,无论读多少次都是值1;哪怕这个过程中事务B修改了数据的值还提交了,但是事务A读到的还是自己事务开始时这个数据的值。
串行化
幻读,不可重复读和可重复读都是针对两个事务同时对某条数据在修改,但是幻读针对的是插入,比如某个事务把所有行的某个字段都修改为了2,结果另外一个事务插入了一条数据,那个字段的值是1,然后就尴尬了。第一个事务会突然发现多出来一条数据,那个数据的字段是1。如果要解决幻读,就需要使用串行化级别的隔离级别,所有事务都串行起来,不允许多个事务并行操作。
MySQL的默认隔离级别是Read Repeatable,就是可重复读,就是说每个事务都会开启一个自己要操作的某个数据的快照,事务期间,读到的都是这个数据的快照罢了,对一个数据的多次读都是一样的。
系统交互
首先,我们使用现在使用mysql的时候,都是直接在工程中引入mysql驱动包,spring boot会自动帮我们建立连接池,底层会和数据库建立网络连接,然后我们通过java程序来进行crud的处理逻辑,然后把sql告诉驱动,由它来告知数据库进行后续的处理。
关键字:连接池
在我们系统中,同一时刻一般都是由多个线程在处理的,因为用户不会商量好什么时候访问。所以在多个用户同时访问的时候,java肯定会同时处理多个请求,也就是需要和mysql进行多次交互。那么如果每次交互都建立一个新的连接,使用完就销毁的话。肯定会有大量的资源耗费在创建、销毁连接这种动作上。
所以一般都是使用一个连接池来控制多个请求。池子里直接拿现有的数据库连接,用完再放回去,等待下一个请求的使用。这样就不用频繁的建立和销毁连接了。连接池会自动维护系统与数据库直接的连接。
这些内容,在我们配置系统数据库的时候都是可以自定义的,如图:
然后由于每个线程都有自己的执行操作流程,所以就会产生多事务并发的问题,这都是老生常谈的了,四个问题对应四个事务的隔离级别巴拉巴拉。
mysql架构
在我们真实的开发过程中,是不需要知道mysql底层是什么样执行,怎么解析,怎么处理,怎么缓存的,它对于我们来说就是一个黑盒。但是。。。
网络连接要交给线程
因为所有的系统运行都是由线程来操作的,那么mysql接收到网络连接之后,肯定是要有一个监听线程先感知到,然后再说请求后面的处理流程
sql接口
当mysql接收到一个网络请求之后,会取出其中的sql语句,交给sql接口去执行。它是mysql的一个组件,专门用来接收sql语句,然后执行后面的操作
查询解析器
sql接口获取到语句之后,就需要这个查询解析器组件。它会把sql语句按照规则来解析,如果是select就去查询,如果是insert语句就去插入。
查询优化器
解析完sql之后,就要看这个语句怎么执行怎么查询数据才是最优解,最节省资源。这里就是处理where后面的条件,该用什么字段来匹配数据,优先用什么字段来匹配数据是最快能定位到数据,用哪个索引是最快速的。
执行器
这一步就已经要到操作层面了,这一步是什么,下一步是什么,会通过执行器来告诉下一个组件
存储引擎
这一步就接触到真正的数据了,根据执行器的指令来操作磁盘或者缓存中的各种数据,有些是直接从内存中取得,有些需要从磁盘中来拿。具体先更新哪个,先查询哪个,是由存储引擎来判断的
大致的流程如图:
未完待续
预告
下一篇是数据更新流程,会涉及到三大日志