菜鸡秋招第一次面试以后……应该好好研究一下索引、事务、死锁了

作业帮面经和感受

作业帮一面面经,有幸收到了二面,过两天会来持续更新;
1.自我介绍然后讲项目背景设计等等
2.域名方面,怎么生成的
3.多进程多线程,进程线程区别
4.多进程并发怎么实现,有什么问题,这个不会
5.多线程会有哪些问题,怎么解决
6.讲一下索引和事物,
7.你的图片服务器项目中,怎么解决脏读幻读问题的
8.死锁的条件以及避免死锁的办法
9.写数据库语句,学生表啥的
10.linux指令
11.讲java的三大特性
12.讲list set 和map
13.hashmap和hashtable的区别
14.处理冲突的办法
15.手写冒泡和快排
面完的知识查漏和一些感受
索引和事务感觉自己掌握的还是不好,所以又转门总结了一下,还有死锁那儿理解的不透彻,最重要的感受是把知识掌握了跟你面试能不能说上来那是两回事,不说了,我滚去学习了……

一、索引

1、什么是索引?为什么要有索引?

简单来说,索引就像一个目录;比如你想在图书馆借一本莫言的小说,一楼存的数学类,二楼医学类,三楼文学类。在三楼一排存的徐志摩的,二排存的莫言的,三排存的林徽因的。索引就相当于引导,有人告诉你三楼二排存的莫言的,你就不用从一楼一本一本的去往上找,这就大大增加了查找速度。

来官方一点:索引能快速找出在某一列中有一特定值的行。不使用索引,mysql必须从第一条记录开始查找,直到找到相关的行。如果表中查询的列有一个索引,mysql能快速到达某个位置去搜索数据文件,而不必查看所有数据。索引是对数据库中一列或多列的值进行排序的一种结构,用B+树实现,它也算一个文件,占据一定的物理空间;

2、 索引的优缺点

advantage:
1、提高查询性能(这个才是最最重要的)
2、创建唯一性索引,保证数据库表中每一行数据的唯一性;
3、加速表和表之间的连接;
4、在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间

disadvantage
1、索引需要占物理空间,你创建的索引也得要用一定的空间来存,毕竟天下没有免费的午餐。
2、当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度。

3、索引的分类

唯一索引:数据列不允许重复,允许为null;一个表允许多个列创建唯一索引;例如,如果在employee表中职员的姓(lname)上创建了唯一索引,则任何两个员工都不能同姓。

主键索引:在数据库中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型,数据列不允许为空,不允许为null;一个表只能有一个主键;

普通索引:就是简单的加速查询,没有唯一性的限制,允许未null;
全文索引:对文本内容进行搜索,解决像 where name like "%word%"这类模糊查询效率比较低的问题;目前只有MyISAM引擎支持;

根据物理地址是否连续又分为聚簇索引和非聚簇索引,现在Myisam使用的是非聚簇索引,InnoDb使用的是聚簇索引;
聚簇索引:在聚簇索引中,表中行的物理顺序与索引的物理顺序一致。一个表只能包含一个聚集索引, 即如果存在聚集索引,就不能再指定CLUSTERED 关键字。一个表中只能有一个聚集索引,但表中的每一列都可以有自己的非聚集索引。
非聚集索引:则表中行的物理顺序与键值的逻辑(索引)顺序不匹配。与非聚集索引相比,聚集索引通常提供更快的数据访问速度。聚集索引更适用于对很少对基表进行增删改操作的情况。

4、索引的建立

在哪儿建立?索引的建立是在数据库的某些列上面
1、在经常需要搜索的列上,可以加快搜索速度,
2、在作为主键的列上,强制该列的唯一性,
3、在经常用作连接的列上,可以加快连接的速度
4、在经常需要排序的列上,利用索引的排序,加快排序时间,
5、在经常使用where子句中的列上,可以加快条件的判断速度

5、 为什么B+ 比 别的树更适合?

首先要明白数据库索引是存储在外部磁盘上的,我们要选的数据结构应该是符合这一特性的;

红黑树的缺点:红黑树的深度过大而造成磁盘 IO 读写过于频繁,而 IO 读写效率很低,这在大规模的数据处理中一点优势也没有;根据磁盘查找存取的次数往往由树的高度所决定,所以要做的改进就是减少树的高度,B树就很合适

B+树比B树好在哪儿?
①B+的磁盘读写代价更低
B+ 的内部结点并没有指向关键字具体信息的指针,因此其内部结点相对B树来说更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。

②B+ 的查询效率更加稳定
由于非叶子结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相同。

③ B树在提高了磁盘 IO 性能的同时,并没有解决元素遍历的效率低下的问题。正是为了解决这个问题,B+树应运而生。B+树只要遍历叶子节点就可以实现整棵树的遍历。而且在数据库中,基于范围的查询是非常频繁的,而 B 树不支持这样的操作

二、事务

1、为什么使用事务

先想一个场景,比如A要给B转200块钱,那就需要两部操作,A账户少200,B账户多200,如果第一步执行成功了,因为一些不知道的原因,第二部没成功B没收到200块钱,这是非常危险的事情,所以就需要事务;
事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。

2、事务的四大特性

事务是作为一个逻辑单元执行的一系列操作,一个逻辑工作单元必须有四个属性,称为 ACID(原子性、一致性、隔离性和持久性)属性,只有这样才能成为一个事务。

原子性:事务中的全部操作在数据库中是不可分割的;对于其数据修改,要么全都执行,要么全都不执行。

一致性:事务在完成时,必须使所有的数据都保持一致状态,从一种正确的状态变为另一种正确的状态。比如两个杯子倒水,A往B里倒一点,B往A里倒一点,到最后,A杯跟B杯加起来的水是没有少的。

隔离性:事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

持久性:一个事务被提交之后,它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响;

3、脏读、幻读不可重复读

在并发状态下事务会出现一些问题,像上面这三种情况;

脏读:某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个回滚了操作,则后一个事务所读取的数据就是脏数据
举例说明:A 给 B 转了100块钱,但是 A 还没有提交,此时 B 查询自己账户,多了100万。然后 A 发现转错人了,回滚了事物。然后 B 100块钱就没了。在这个过程中 B 查到了没有提交的那100块钱,这就是脏读。

不可重复读:在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
举例:A账户有100块钱,A第一次查询时是100,B取走了50,A在查询就是50;对A来说两次结果不一致就是不可重复读;

幻读:在一个事务的两次查询中数据不一致,发现了原来没有的数据,
举例:例如有一个事务A查询了几列数据,而另一个事务B却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的,对A来说就产生了幻读;
ps:不可重复读和幻读很像,不可重复读侧重于修改,幻读侧重于新增和删除;

4、事物的隔离级别

SQL 标准定义了四个隔离级别去解决上述问题,隔离级别越高,产生的问题就越少;
在这里插入图片描述

读取未提交READ-UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。

读取已提交READ-COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。(Oracle默认的隔离级别)

可重复读REPEATABLE-READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。(mysql默认的隔离级别

可串行化SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容):,但是你要知道的是InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)**并不会有任何性能损失。

三、死锁

1、死锁的概念

死锁是指两个或两个以上的进程(线程)在运行过程中因争夺资源而造成的一种僵局,若无外力作用,这些进程(线程)都将无法向前推进 ,这时就形成了死锁。处于死锁状态的进程称为死锁进程;
比如一扇门,你要出我要进,你在等我让,我在等你让,这时就陷入了死循环,就形成了死锁。

2、死锁产生的条件

先来看两个概念: 可抢占资源和不可抢占资源
可抢占资源:指某进程在获得这类资源后,该资源可以再被其他进程或系统抢占。对于这类资源是不会引起死锁的。CPU 和主存均属于可抢占性资源。

不可抢占资源:一旦系统把某资源分配给该进程后,就不能将它强行收回,只能在进程用完后自行释放。磁带机、打印机等属于不可抢占性资源

竞争不可抢占资源引起死锁如:共享文件时引起死锁系统中拥有两个进程P1和P2,它们都准备写两个文件F1和F2。而这两者都属于可重用和不可抢占性资源。如果进程P1在打开F1的同时,P2进程打开F2文件,当P1想打开F2时由于F2已结被占用而阻塞,当P2想打开1时由于F1已结被占用而阻塞,此时就会无线等待下去,形成死锁。进程推进顺序不当时也会引起死锁

产生死锁的四个必要条件
(1)互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源;比如有一间单人自习室,我在里面学习,你就不能进来学习,你要进来得等我学完出来了

(2)请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放;我在现在这个自习室里,我还觉得不够,又对你所在的自习室发出请求,但你正在用,这时我又不愿意把自己的自习室让出来,这就是请求和保持;

(3)不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放,就是我在自习室里你不能把我撵出来;

(4)循环等待条件:是指进程发生死锁后,必然存在一个进程–资源之间的环形链;

3、处理死锁的基本方法

1.预防死锁:通过设置一些限制条件,去破坏产生死锁必要条件的一个或多个来预防死锁,让系统不会产生死锁,两种办法
①资源一次性分配:可以破坏请求和保持条件;
可剥夺资源:即当某进程新的资源未满足时,释放已占有的资源(破坏不可剥夺条件)
②资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)

2.避免死锁:在资源分配过程中,使用某种方法避免系统进入不安全的状态,从而避免发生死锁,在使用前判断,只允许不会产生死锁的进程申请资源
①银行家算法
原理简介:把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:
(1) 当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
(2) 顾客可以分期贷款,但贷款的总数不能超过最大需求量;
(3) 当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
(4) 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金.

操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程本次申请的资源数是否超过了该资源所剩余的总量。若超过则拒绝分配资源,若能满足则按当前的申请量分配资源,否则也要推迟分配。

②避免多次锁定:尽量避免同一个线程对多个 锁进行锁定。

③具有相同的加锁顺序:(给锁添加顺序)如果多个线程需要对多个 Lock 进行锁定,则应该保证它们以相同的顺序请求加锁。

④使用定时锁:程序在调用 acquire() 方法加锁时可指定 timeout 参数,该参数指定超过 timeout 秒后会自动释放对 Lock 的锁定,这样就可以解开死锁了。

⑤死锁检测:死锁检测是一种依靠算法机制来实现的死锁预防机制,它主要是针对那些不可能实现按序加锁,也不能使用定时锁的场景的。

3.检测死锁:允许死锁的发生,但是通过系统的检测之后,采取一些措施,将死锁清除掉

4.解除死锁:当检测出死锁后,便采取适当措施将进程从死锁状态中解脱出来。主要有两个方法
①从别的进程中抢占足够数量的资源分配给死锁进程来解除死锁状态
②终止进程,终止或撤销系统中一个或多个死锁进程;

猜你喜欢

转载自blog.csdn.net/chris__x/article/details/107905395