202003招银网络科技面经

一面

1.1 SpringMvc的过程

流程说明:

1.客户端(浏览器)发送请求,直接请求到DispatcherServlet。

2.DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。

3.解析到对应的Handler(也就是我们平常说的Controller控制器)。

4.HandlerAdapter会根据Handler来调用真正的处理器来处理请求和执行相对应的业务逻辑。

5.处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是逻辑上的View。

6.ViewResolver会根据逻辑View去查找实际的View。

7.DispatcherServlet把返回的Model传给View(视图渲染)。

8.把View返回给请求者(浏览器)

1.2 SpringBoot的启动流程

  1. 通过 SpringFactoriesLoader 加载 META-INF/spring.factories 文件,获取并创建 SpringApplicationRunListener 对象
  2. 然后由 SpringApplicationRunListener 来发出 starting 消息
  3. 创建参数,并配置当前 SpringBoot 应用将要使用的 Environment
  4. 完成之后,依然由 SpringApplicationRunListener 来发出 environmentPrepared 消息
  5. 创建 ApplicationContext
  6. 初始化 ApplicationContext,并设置 Environment,加载相关配置等
  7. 由 SpringApplicationRunListener 来发出 contextPrepared 消息,告知SpringBoot 应用使用的 ApplicationContext 已准备OK
  8. 将各种 beans 装载入 ApplicationContext,继续由 SpringApplicationRunListener 来发出 contextLoaded 消息,告知 SpringBoot 应用使用的 ApplicationContext 已装填OK
  9. refresh ApplicationContext,完成IoC容器可用的最后一步
  10. 由 SpringApplicationRunListener 来发出 started 消息
  11. 完成最终的程序的启动
  12. 由 SpringApplicationRunListener 来发出 running 消息,告知程序已运行起来了

1.3 SpringBoot的自动装配

1.容器在启动的时候Application.run,会调用EnableAutoConfigurationImportSelector.class的selectImports方法(其实是其父类的方法)
2.selectImports方法最终会调用SpringFactoriesLoader.loadFactoryNames方法来获取一个全面的常用BeanConfiguration列表
3.loadFactoryNames方法会读取FACTORIES_RESOURCE_LOCATION(也就是spring-boot-autoconfigure.jar 下面的spring.factories),获取到所有的Spring相关的Bean的全限定名ClassName,大概120多个
4.selectImports方法继续调用filter(configurations, autoConfigurationMetadata);这个时候会根据这些BeanConfiguration里面的条件,来一一筛选,最关键的是
@ConditionalOnClass,这个条件注解会去classpath下查找,jar包里面是否有这个条件依赖类,所以必须有了相应的jar包,才有这些依赖类,才会生成IOC环境需要的一些默认配置Bean
5.最后把符合条件的BeanConfiguration注入默认的EnableConfigurationPropertie类里面的属性值,并且注入到IOC环境当中
链接请见:springBoot自动装配

1.4 SpringMvc和SpringBoot的区别

1.springMvc需要加载很多配置,springBoot可以自动装配这些类及其配置
2.约定大约配置
3.springMvc还需要外部依赖tomcat,而SpringBoot内部依赖了tomcat不需要再额外部署tomcat了

1.5 IOC的概念、原理和设计模式

IOC(Inversion Of Controll,控制反转)是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由给Spring框架来管理。IOC在其他语言中也有应用,并非Spring特有。IOC容器是Spring用来实现IOC的载体,IOC容器实际上就是一个Map(key, value),Map中存放的是各种对象。

将对象之间的相互依赖关系交给IOC容器来管理,并由IOC容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。IOC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。在实际项目中一个Service类可能由几百甚至上千个类作为它的底层,假如我们需要实例化这个Service,可能要每次都搞清楚这个Service所有底层类的构造函数,这可能会把人逼疯。如果利用IOC的话,你只需要配置好,然后在需要的地方引用就行了,大大增加了项目的可维护性且降低了开发难度。

Spring时代我们一般通过XML文件来配置Bean,后来开发人员觉得用XML文件来配置不太好,于是Sprng Boot注解配置就慢慢开始流行起来。

XML读取 -> Resource解析 -> BeanDefinition注册 -> BeanFactory

使用的设计模式有:工厂模式如,BeanFactory和ApplicationContextFactory;单例模式如,spring默认都是单例的,在像DefinitionMap初始化的时候使用了单例模式,确保只生成有一个实例

1.6 AOP概念、原理和设计模式

AOP(Aspect-Oriented Programming,面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可扩展性和可维护性。

Spring AOP是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP就会使用JDK动态代理去创建代理对象,源代码里面是用了一个if (isInterface)来做了判断;而对于没有实现接口的对象,就无法使用JDK动态代理,转而使用CGlib动态代理生成一个被代理对象的子类来作为代理。

1.7 Spring事务的隔离级别

在TransactionDefinition接口中定义了五个表示隔离级别的常量:

ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。

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

ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

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

ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

1.8 Spring事务有哪几种事务传播行为

在TransactionDefinition接口中定义了八个表示事务传播行为的常量。

支持当前事务的情况:

PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)。

不支持当前事务的情况:

PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。

PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。

PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

其他情况:

PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED。

1.9 Mysql数据库数据量达到亿级别的大表,如何优化?垂直分表怎么分?

水平分表,垂直分表,创建索引

  1. 数据库设计和表创建时就要考虑性能,遵循数据库设计范式。
    • 表字段避免null值出现,null值很难查询优化且占用额外的索引空间,推荐默认数字0代替null
    • 尽量使用int而非bigint,当然能使用tinyint、smallint、medium_int更好
    • 使用枚举或整数代替字符串类型
    • 单表不要有太多字段,建议在20以内
    • 用整型来存IP
    • 索引并不是越多越好,要根据查询有针对性的创建,考虑在where和order by命令上涉及的列建立索引,可根据explain来查看是否用了索引还是全表扫描
    • 应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描
    • 值分布很稀少的字段不适合建索引,例如“性别”这种只有两三个值的字段
    • 字符字段只建前缀索引
    • 字符字段最好不要做主键
    • 使用多列索引时注意顺序和查询条件保持一致,同时删除不必要的单例索引
  2. 优化sql和索引。
    • 使用limit对查询结果的记录进行限定
    • 避免select *,将需要查找的字段列出来
    • 使用连接(join)来代替子查询 拆分大的delete或insert语句
    • 可通过开启慢查询日志来找出较慢的SQL
    • 不做列运算:SELECT id WHERE age + 1 = 10,任何对列的操作都将导致表扫描,它包括数据库教程函数、计算表达式等等,查询时要尽可能将操作移至等号右边
    • sql语句尽可能简单:一条sql只能在一个cpu运算;大语句拆小语句,减少锁时间;一条大sql可以堵死整个库
    • OR改写成IN:OR的效率是n级别,IN的效率是log(n)级别,in的个数建议控制在200以内
    • 不用函数和触发器,在应用程序实现
    • 避免%xxx式查询 少用JOIN 使用同类型进行比较,比如用’123’和’123’比,123和123比 尽量避免在WHERE子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描 对于连续数值,使用BETWEEN不用IN:SELECT id FROM t WHERE num BETWEEN 1 AND 5 列表数据不要拿全表,要使用LIMIT来分页,每页数量也不要太大
      优点:不影响现有业务,源程序不需要修改代码,成本最低。
      缺点:有优化
  3. 强行建分区
    MySQL在5.1版引入的分区是一种简单的水平拆分,用户需要在建表的时候加上分区参数,对应用是透明的无需修改代码对用户来说,分区表是一个独立的逻辑表,但是底层由多个物理子表组成,实现分区的代码实际上是通过对一组底层表的对象封装,但对SQL层来说是一个完全封装底层的黑盒子。MySQL实现分区的方式也意味着索引也是按照分区的子表定义,没有全局索引用户的SQL语句是需要针对分区表做优化,SQL条件中要带上分区条件的列,从而使查询定位到少量的分区上,否则就会扫描全部分区,可以通过EXPLAIN PARTITIONS来查看某条SQL语句会落在那些分区上,从而进行SQL优化,我测试,查询时不带分区条件的列,也会提高速度,故该措施值得一试。
    可以让单表存储更多的数据
    • 分区表的数据更容易维护,可以通过清除整个分区批量删除大量数据,也可以增加新的分区来支持新插入的数据。另外,还可以对一个独立分区进行优化、检查、修复等操作
    • 部分查询能够从查询条件确定只落在少数分区上,速度会很快
    • 分区表的数据还可以分布在不同的物理设备上,从而高效利用多个硬件设备
    • 可以使用分区表赖避免某些特殊瓶颈,例如InnoDB单个索引的互斥访问、ext3文件系统的inode锁竞争
    • 可以备份和恢复单个分区
  4. 分表
    水平分表、垂直分表
    分表就是把一张大表,按照如上过程都优化了,还是查询卡死,那就把这个表分成多张表,把一次查询分成多次查询,然后把结果组合返回给用户。分表分为垂直拆分和水平拆分,通常以某个字段做拆分项。比如以id字段拆分为100张表: 表名为 tableName_id%100但:分表需要修改源程序代码,会给开发带来大量工作,极大的增加了开发成本,故:只适合在开发初期就考虑到了大量数据存在,做好了分表处理,不适合应用上线了再做修改,成本太高!!!而且选择这个方案,都不如选择我提供的第二第三个方案的成本低!故不建议采用
  5. 分库
    读写库分离
  6. 加缓存,memcached,redis
  7. 升级数据库类型,换一种100%兼容mysql的数据库。缺点:多花钱
  8. 一步到位,大数据解决方案,更换成nosql数据库。
    优点:没有数据容量瓶颈
    缺点:需要修改源程序代码,影响业务,总成本最高

1.10 memcached和redis的区别?redis支持的数据类型?

memcached和redis的区别

1.11 redis的回收策略

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

no-enviction(驱逐):禁止驱逐数据

1.12 MySQL数据库引擎,MyISAM和InnoDB的区别?

  1. MyISAM
    MyISAM引擎是MySQL 5.1及之前版本的默认引擎,它的特点是:
  • 不支持行锁,读取时对需要读到的所有表加锁,写入时则对表加排它锁
  • 不支持事务
  • 不支持外键
  • 不支持崩溃后的安全恢复
  • 在表有读取查询的同时,支持往表中插入新纪录
  • 支持BLOB和TEXT的前500个字符索引,支持全文索引
  • 支持延迟更新索引,极大提升写入性能 对于不会进行修改的表,支持压缩表,极大减少磁盘空间占用
  1. InnoDB
    InnoDB在MySQL 5.5后成为默认索引,它的特点是:
  • 支持行锁,采用MVCC来支持高并发
  • 支持事务
  • 支持外键
  • 支持崩溃后的安全恢复
  • 不支持全文索引

总体来讲,MyISAM适合SELECT密集型的表,而InnoDB适合INSERT和UPDATE密集型的表

1.13 主键和索引的区别?

  1. 主键是为了标识数据库记录唯一性,不允许记录重复,且键值不能为空,主键也是一个特殊索引.
  2. 数据表中只允许有一个主键,但是可以有多个索引.
  3. 使用主键会数据库会自动创建主索引,也可以在非主键上创建索引,方便查询效率.
  4. 索引可以提高查询速度,它就相当于字典的目录,可以通过它很快查询到想要的结果,而不需要进行全表扫描.
  5. 主键索引外索引的值可以为空.
  6. 主键也可以由多个字段组成,组成复合主键,同时主键肯定也是唯一索引.
  7. 唯一索引则表示该索引值唯一,可以由一个或几个字段组成,一个表可以有多个唯一索引.

1.14 创建联合索引好还是多个单索引好?

看情况
1.如果是经常使用两个不同的属性进行查询的时候,并且还需要根据第二个字段的排序,那么就使用联合索引,只能按照组合索引的顺序使用。
2.如果是单个索引那么就好在灵活,可以在很多场景生效。

1.15 Mysql索引在什么情况下会失效?

失效的场景

  • like 查询时’%'在前面
  • 组合索引时,把后面的字段写在前面
  • or 查询时,只有or前后的两个列都是索引时,才会使用索引,否则不使用
  • not in和not exist

1.16 MySql的索引是基于什么实现的?B树和B+树

mysql树是基于b+树实现的,b+树不是二叉树。

  • b树在所有的节点都会有数据,而b+树只会在叶子节点保存数据,并且在叶子节点之间有指针,指向下一个叶子节点
  • b+树在非叶子节点只用来索引
  • b+树中间节点不保存数据,所以树更矮胖,磁盘页能容下更多的数据

1.17 JVM的内存模型?垃圾回收主要回收哪一块?回收的过程是怎样的?

自行了解

1.18 HashMap的结构?key冲突是指什么?

hashMap是数组加链表的结构,一个hash值对应着一个数组节点,相同hash,不能key的结点就会产生冲突,这时候,hashmap允许在数组下挂一个链表来解决冲突。
或根据key获取value的时,先计算hash值,找到数组节点,在根据key值去对比链表的key值,就能获取到value值了

1.19 ConcurrentHashMap的实现?

1.7之前ConcurrentHashMap是根据分段锁segamet来实现线程安全的,数据结构仍然是数组+链表。
1.8之后数据结构变成了数组+链表/红黑树的形式,去掉了分段锁的概念,当链表长达大于8时,链表就会转换为红黑树,当红黑树节点个数小于6时就会转成链表,至于为啥是8和6这两个数值,仍待研究。此版本的线程安全是通过CAS和sync来完成的。

1.20 简单介绍下CAS?

cas是比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令,是乐观锁,每次执行前,先假定没有锁冲突,不加锁,它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新的给定值。
会出现ABA问题,如果线程从内存中获取到的值时A,然后处理后,拿着A,C去内存中修改。但是此时内存中的数据已经被改成B又改成A了,这种就不会发现,对某些业务逻辑可能有影响,我们可以给节点加一个时间戳,同时对比值和时间戳就行。AtomitcInteger已经实现了添加时间戳来解决ABA问题。

1.21 Kafka一般适用于什么场景?

1.22 队列和栈的区别?

队列是先进先出的,粘是先进后出的

1.23 简单介绍下mybatisGenerator

mybatisGenerator是用来初始化mybatis代码的,在项目刚刚创建的时候,使用这个能快速的创建基本类,还可以用mybatisPlus来替代Mybatis,mybatisPlus不用写sql语句,直接配置就好了,优点就是:可以兼容Oracle,mysql等不能类型的,不同版本的RMDB类型数据库。

二面

2.1 redis没有设置过期策略,内存满了怎么处理

1.增加内存
2.设置过期策略
3.写到磁盘里面
4.搭建redis集群

2.2 redis的持久化机制

RDB:快照形式
AOF:记录脚本形式
两种持久化机制

2.3 hive的内部表外部表的区别,用sql语句创建表

删除内部表,删除表元数据和数据
删除外部表,删除元数据,不删除数据
内部表和外部表的使用选择:

  • 大多数情况,他们的区别不明显,如果数据的所有处理都在 Hive 中进行,那么倾向于 选择内部表,但是如果 Hive 和其他工具要针对相同的数据集进行处理,外部表更合适。
  • 使用外部表访问存储在 HDFS 上的初始数据,然后通过 Hive 转换数据并存到内部表中
  • 使用外部表的场景是针对一个数据集有多个不同的 Schema
  • 通过外部表和内部表的区别和使用选择的对比可以看出来,hive 其实仅仅只是对存储在 HDFS 上的数据提供了一种新的抽象。而不是管理存储在 HDFS 上的数据。所以不管创建内部 表还是外部表,都可以对 hive 表的数据存储目录中的数据进行增删操作。

2.4 hive存在过多的小文件怎么办?

使用cron定时把他们汇总起来

2.5 灰度发布用于什么场景?

新旧系统交替时,线上验证新系统是否有bug

2.6 如何做任务的上下游的依赖调度?

使用zk,子节点监听父节点即可。

2.7 sql执行问题

tablea 中有urid,urname
tableb 中有usid,funid
tablec 中有funid,funname

delete from tablea
 where urid in
 (
 select urid from tableb
 where funid in
 (
  select funid from tablec
  where funname like '%11%'
 )
)

这个sql问题在于,tableb根本没有urid这个字段,那么这个sql会执行出来啥结果呢?
当tableb没有这个字段,即在本地查找列名没有找到的情况下,就回去他的上级tablea中查找,如果funid有一个符合条件的,那么就会把全部的tablea中全部的数据删除掉。可以自行验证。

2.7 平时如何做代码Review的?

用sonar

2.8 kafka异地容灾如何做?

2.9 项目管理相关

原创文章 25 获赞 22 访问量 1249

猜你喜欢

转载自blog.csdn.net/a1240466196/article/details/105450500