数据库概念
1. ACID 讲一下
(阿里校招)
ACID是事物的四个特性。分别是 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability) 。
- 原子性是指事物是一个不可分割的工作单位,事物中的操作要么都发生,要么都不发生。最经典的就是转账案例,我们把转入和转出当做一个事物的话,就需要在SQL中显式指定开启事务。
- 一致性是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性 。我们可以从数据库层面和业务层面两方面来保证,数据库层面我们可以设置触发器,外键,表,行约束等来保证,业务层面就是我们Java工程师的工作啦
- 隔离性指的是多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。 多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。 这个点又引申出了下面两道题,以及后边的加锁和阻塞
- 持久性意味着即使出现了任何事故比如断电等,事务一旦提交,则持久化保存在数据库中,不会被回滚
2. 说一下脏读,不可重复读和幻读
- 脏读: 意味着一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚的。即这个事物读取的数据是不正确的
- 不可重复读: 在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。即这个事物在读的过程中被修改了
- 幻读:当一个事物对整个table进行修改之后,第二个事物向表中插入了一行数据,此时第一个事物发现了新插入的没有修改的数据行,好像发生了幻觉一样
3. 数据库的隔离级别
读未提交RU
-
一个事务还没提交时,它做的变更就能被别的事务看到
-
会出现幻读,不可重复读,脏读
-
更新数据时加上行级共享锁,事物结束即释放
-
读已提交RC
- 一个事务提交之后,它做的变更才会被其他事务看到
- 会出现幻读,不可重复读,不会出现脏读
- 写数据加行级排他锁,这样写过程是无法读取的,直到事务处理完毕才释放排他锁,给读的数据加行级共享锁,这样读的时候也是无法写的,但是一旦读完该行就释放共享锁
- MySQL会在SQL语句开始执行时创建一个视图
-
可重复读RR
- 一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的
- 会出现幻读,不会出现不可重复读,脏读
- 给写的数据加行级排他锁,事务结束释放,给读的数据加行级共享锁,事务结束后释放
- MySQL会在事物开始时创建一个一致性视图*(接下面的MVCC)*,事物结束时销毁
-
可串行化S
- 当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行
- 不会出现幻读,不可重复读,脏读
- 事务读数据则加表级共享锁,事务写数据则加表级排他锁
- 不区分快照度与当前读
-
其中,Oracle和SQLServer都是读已提交,但MySQL默认的隔离级别是可重复读 ,这是一个MySQL5.0之前的上古遗留版本问题。当时的binlog只有STATEMENT格式,用RC会出现bug。
当面试官问我们项目用的哪个隔离级别,就我自己来说,如果看我之前的文章,我写过我搭建了一个博客,对于博客来说,我肯定要说读已提交。这样的并发度更高,同时,在我们的互联网项目中可以接受重复读带来的一些不便。
同时,既然问到了数据库的隔离级别,那么离下面的锁也不远了
4. 三大范式
- 第一范式: 所有字段值都是不可分解的原子值 。例如有一个列是电话号码一个人可能有一个办公电话一个移动电话。第一范式就需要拆开成两个属性。
- 第二范式:非主属性完全函数依赖于候选键。如PersonID,ProductID,ProductName,PersonName可以看到,OrderID和ProductID是联合主键,但是ProductName是依赖于ProductID的,只依赖了部分主键,没有依赖全部主键。需要拆分成三个表:
PersonID, PersonName
,ProductID, ProductName
和PersonID, ProductID
- 第三范式: 每一列数据都和主键直接相关,而不能间接相关
- 如OrderID,ProductID,ProductName,OrderID是主键,但是ProductID依赖了OrderID,而ProductName依赖了ProductID,等于说是间接依赖了OrderID,所以需要拆分为两个表:
OrderID, ProductID
和ProductID, ProductName
这里需要指明范式不是最好的,我们需要混合使用范式和反范式
- 范式的优点:因为相对来说有较少的重复数据,范式化的更新操作要比反范式快。同时范式化需要更少的distinct和order by
- 范式化缺点:通常需要关联,不仅代价昂贵,也可能会使的一些索引无效
常用的反范式方法:
-
复制:在两个表中根据实际业务情况存储部分相同的字段列,即有利于查询,也不会把表搞的太大
-
缓存:对于需要多次join查询的表,可以在一个表中加入一个缓存列,用来缓存所join表的部分常用数据,如count等,我们需要实时更新该缓存
-
5. 说一下内连接和外连接
内连接也叫自然连接,只有两个表相匹配的行才能在结果集中出现。返回的结果集选取两个表中所匹配的数据,舍弃不匹配的数据
1 | select fieldlist from table1 [inner] join table2 on table1.column = table2.column |
---|
- 内连接保证两个表中的所有行都满足条件,而外连接则不然,外连接不仅仅包含符合连接条件的行,而且还包括左表(左外连接),右表(右外连接),或者两个边表(全外连接)中的所有数据行
1 | select fieldlist from table1 left/ right outer join table2 on table1.column = table2.column |
---|
- 目前(8.0)MySQL不支持全外连接
MySQL索引
索引是一种数据结构,用于帮助我们在大量数据中快速定位到我们想要查找的数据。可以加快查的速度,但是会增加容量,降低增,删,改的速度
1. MySQL有哪几种索引类型,各自特点
常见的MySQL索引结构有B-树索引,B+树索引,Hash索引和全文索引
B-Tree索引
-
因为存储引擎不用进行全表扫描来获取数据,直接从索引的根节点开始搜索,从而能加快访问数据的速度
-
B-Tree对索引是顺序组织存储的,很适合查找范围数据
-
适用于全键值、键值范围或者键前缀查找*(根据最左前缀查找)*
-
限制:对于联合索引来说,如果不是从最左列开始查找,则无法使用索引;不能跳过索引中的列
-
B+Tree索引
- 是B-Tree索引的变种&#x