[关闭]
@MRsunhuimin 2019-11-14T15:11:10.000000Z 字数 8611 阅读 176

第一次模拟面试

面试问题总结


1. 左连接和内连接的区别?

    左连接是以左表为基准,显示所有数据;内连接,只显示两个表中有联系(都存在)的所有数据,

2. 数据库分组函数(5个)

函数名 描述
count(expr) 返回满足SELECT条件的记录总和数,如 SELECT COUNT(*)…
sum(expr) 返回数字字段或表达式列作统计,返回一列的总和
avg(expr) 通常为数值字段或表达列作统计,返回一列的平均值
max(expr) 可以为数值字段、字符字段或表达式列作统计,返回最大的值
min(expr) 可以为数值字段、字符字段或表达式列作统计,返回最小的值
    1. 数据类型是有规定的,必须是字符型或数字
    2. expr的类型不能是空,如果是空,则不计入其中

3. SpringBoot和SpringMVC的区别

spring boot只是一个配置工具,整合工具,辅助工具.

springmvc是框架,项目中实际运行的代码

    Spring 框架就像一个家族,有众多衍生产品例如 boot、security、jpa等等。但他们的基础都是Spring 的ioc和 aop. ioc 提供了依赖注入的容器, aop解决了面向横切面的编程,然后在此两者的基础上实现了其他延伸产品的高级功能。

    Spring MVC是基于Servlet 的一个 MVC 框架主要解决 WEB 开发的问题,因为 Spring 的配置非常复杂,各种XML、 JavaConfig、hin处理起来比较繁琐。于是为了简化开发者的使用,从而创造性地推出了Spring boot,约定优于配置,简化了spring的配置流程。

    说得更简便一些:Spring最初利用“工厂模式”(DI)和“代理模式”(AOP)解耦应用组件。大家觉得挺好用,于是按照这种模式搞了一个 MVC框架(一些用Spring 解耦的组件),用开发 web 应用( SpringMVC )。然后发现每次开发都写很多样板代码,为了简化工作流程,于是开发出了一些“懒人整合包”(starter),这套就是 Spring Boot。

3.1 Spring MVC的功能

Spring MVC提供了一种轻度耦合的方式来开发web应用。

    Spring MVC是Spring的一个模块,式一个web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。解决的问题领域是网站应用程序或者服务开发——URL路由、Session、模板引擎、静态Web资源等等。

3.2 Spring Boot的功能

Spring Boot实现了自动配置,降低了项目搭建的复杂度。

    众所周知Spring框架需要进行大量的配置,Spring Boot引入自动配置的概念,让项目设置变得很容易。Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box),大部分的Spring Boot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。

    Spring Boot只是承载者,辅助你简化项目搭建过程的。如果承载的是WEB项目,使用Spring MVC作为MVC框架,那么工作流程和你上面描述的是完全一样的,因为这部分工作是Spring MVC做的而不是Spring Boot。

    对使用者来说,换用Spring Boot以后,项目初始化方法变了,配置文件变了,另外就是不需要单独安装Tomcat这类容器服务器了,maven打出jar包直接跑起来就是个网站,但你最核心的业务逻辑实现与业务流程实现没有任何变化。
  • 所以,用最简练的语言概括就是:
  • Spring 是一个“引擎”;
  • Spring MVC 是基于Spring的一个 MVC 框架;
  • Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。

4. SpringBoot中配置文件的加载顺序

4.1、存放目录

    Application属性文件,按优先级排序,位置高的将覆盖位置
    当前项目目录下的一个/config子目录
    当前项目目录
    项目的resources即一个classpath下的/config包
    项目的resources即classpath根路径(root)

4.2、读取顺序

    如果在不同的目录中存在多个配置文件,它的读取顺序是:
    1、config/application.properties(项目根目录中config目录下)
    2、config/application.yml
    3、application.properties(项目根目录下)
    4、application.yml
    5、resources/config/application.properties(项目resources目录中config目录下)
    6、resources/config/application.yml
    7、resources/application.properties(项目的resources目录下)
    8、resources/application.yml

    顺序可以通过实验验证:
    1~8 个位置 分别定义不同的 server 端口号 9001~9008
    即可验证结果顺序
    注:
    1、如果同一个目录下,有application.yml也有application.properties,默认先读取application.properties。
    2、如果同一个配置属性,在多个配置文件都配置了,默认使用第1个读取到的,后面读取的不覆盖前面读取到的。
    3、创建SpringBoot项目时,一般的配置文件放置在项目的resources目录下,因为配置文件的修改,通过热部署不用重新启动项目,而热部署的作用范围是classpath下

4.3、配置文件的生效顺序,会对值进行覆盖

    @TestPropertySource 注解
    命令行参数
    Java系统属性(System.getProperties())
    操作系统环境变量
    只有在random.*里包含的属性会产生一个RandomValuePropertySource
    在打包的jar外的应用程序配置文件(application.properties,包含YAML和profile变量)
    在打包的jar内的应用程序配置文件(application.properties,包含YAML和profile变量)
    在@Configuration类上的@PropertySource注解
    默认属性(使用SpringApplication.setDefaultProperties指定)

4.4、配置随机值

    roncoo.secret={random.value} roncoo.number={random.int}
    roncoo.bignumber={random.long} roncoo.number.less.than.ten={random.int(10)}
    roncoo.number.in.range=${random.int[1024,65536]}

    读取使用注解:@Value(value = "${roncoo.secret}")

    注:出现黄点提示,是要提示配置元数据,可以不配置

4.5、属性占位符

    当application.properties里的值被使用时,它们会被存在的Environment过滤,所以你能够引用先前定义的值(比如,系统属性)
    roncoo.name = www.roncoo.com
    roncoo.desc = ${roncoo.name} is a domain name

4.6、其他配置的介绍

    端口配置
    server.port=8090
    时间格式化
    spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
    时区设置
    spring.jackson.time-zone=Asia/Chongqing

备注
    手动加载配置文件优先级大于自动加载优先级
    高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置
    项目打包时,只打包根目录下的src文件夹,所以根目录文件夹中的配置全部失效

5. 配置文件几种格式?properties与yml之间的比较

    两种格式。
    1. 在properties文件中是以”.”进行分割的, 在yml中是用”:”进行分割;
    2. yml的数据格式和json的格式很像,都是K-V格式,并且通过”:”进行赋值;
    3. 在yml中缩进一定不能使用TAB,否则会报很奇怪的错误;(缩进只能用空格!!!!)
    4. 每个k的冒号后面一定都要加一个空格;
    5. yml中的数据是有序的,properties中的数据是无序的。在一些需要路径匹配的的配置中,顺序就显得尤为重要,此时我们一般采用yml

6. @SpringBootApplication注解?

  • @SpringBootApplication 被 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解所修饰,换言之 Springboot 提供了统一的注解来替代以上三个注解,简化程序的配置。

  • @Configuration 是一个类级注释,指示对象是一个bean定义的源。@Configuration 类通过 @bean 注解的公共方法声明bean。

  • @Bean 注释是用来表示一个方法实例化,配置和初始化是由 Spring IoC 容器管理的一个新的对象。
  • 通俗的讲 @Configuration 一般与 @Bean 注解配合使用,用 @Configuration 注解类等价与 XML 中配置 beans,用 @Bean 注解方法等价于 XML 中配置 bean。

  • @EnableAutoConfiguration 注解的类所在的包有特定的意义,并且作为默认配置使用。例如,当扫描 @Entity类的时候它将本使用。通常推荐将 @EnableAutoConfiguration 配置在 root 包下,这样所有的子包、类都可以被查找到。

  • @ComponentScan为 @Configuration注解的类配置组件扫描指令。同时提供与 Spring XML’s context:component-scan 元素并行的支持。

  • @ComponentScan 注解会自动扫描指定包下的全部标有 @Component注解 的类,并注册成bean,当然包括 @Component 下的子注解@Service、@Repository、@Controller。@ComponentScan 注解没有类似 context:exclude-filter、context:include-filte的属性。

7. 扫包的注解?

    @ComponentScan(value = {"com.hesp.controller", "com.hesp.service", "com.hesp.config","com.hesp.pojo","com.hesp.utils"})
    @MapperScan("com.hesp.dao")

8. @MapperScan扫的是什么?

    扫的是Dao包(com.hz.dao)

9. 项目做的是第几期?

    第一期
    但是有二期的开发计划,因为现在平台主要面对的是个体服务人员,后期准备引进家政公司进行合作。

10. 项目是给谁做的的?多少钱?开发周期多久?你写了多久代码?

    项目是给别的公司做的;项目大概20多万;项目从立项到结束(项目周期)大概7个月左右,开发周期(敲代码)三个月左右,

11. 数据库参与设计了吗?多少张表?

    错误回答:参与了;至少200+张表
    正确回答:数据库我并没有参与设计,但是参与讨论了数据库。数据库具体有多少张表我还不太清楚,因为这方面是由我们的项目经理负责的

12. 你在项目中遇到难点和问题是什么?

    在项目中我们有做了一个抢购优惠券的秒杀模块,技术难点是解决高并发。在那个模块里面我们用到了Redis缓存数据库。
    在具体实现中,我们将准备秒杀的优惠券存放到Redis数据库里,然后当用户在适当时间点击秒杀按钮后,如果该用户抢到了优惠券,那么Redis数据库里存储的优惠券数量减一,提示给用户已抢到;当Redis数据库里的优惠券数量为0时,提示用户已告罄。
    在第一次做的时候我们使用的是对Redis方法加锁和解锁,后来发现使用ActiveMQ消息队列方法更合理,能够用更少的代码去实现。同时我们使用JmsListener监听消息队列,确保一次只有一个用户能够抢到优惠券。
  1. package com.hz.controller;
  2. import com.hz.utils.ActiveMQUtils;
  3. import com.hz.utils.RedisUtil;
  4. import com.hz.vo.Message;
  5. import org.springframework.jms.annotation.JmsListener;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. import org.springframework.web.bind.annotation.RestController;
  8. import javax.annotation.Resource;
  9. @RestController
  10. public class QgController {
  11. // 加锁的方法
  12. // @Resource
  13. // private RedisUtil redisUtil;
  14. //
  15. // @RequestMapping("/qg")
  16. // public String qg(String userId,String goodsId){
  17. //
  18. // String lockkey = "lock_goods_"+goodsId;
  19. // while (!redisUtil.lock(lockkey,60L)){
  20. // try {
  21. // Thread.sleep(2000);
  22. // }catch (InterruptedException e){
  23. // e.printStackTrace();
  24. // }
  25. // }
  26. //
  27. // String res = "";
  28. // String flag = redisUtil.getStr(userId+":"+goodsId);
  29. // if(flag!=null&&"1".equals(flag)){
  30. //
  31. // redisUtil.unLock(lockkey);//解锁
  32. // return "用户"+userId+"已经抢购过此商品!";
  33. // }
  34. //
  35. // String stock = redisUtil.getStr("goods_"+goodsId);
  36. // int stockgoods = Integer.parseInt(stock);
  37. // if(stockgoods>=1){
  38. // stockgoods--;
  39. // redisUtil.setStr("goods_"+goodsId,stockgoods+"");
  40. // //添加用户购买记录
  41. // redisUtil.setStr("qg:"+userId+":"+goodsId,"1");
  42. // res = "用户"+userId+"抢到一个商品!";
  43. // }else{
  44. //
  45. // res = "库存不足!用户"+userId+"没有抢到";
  46. // }
  47. // redisUtil.unLock(lockkey);//解锁
  48. // return res;
  49. // }
  50. // ActiveMQ消息队列方法
  51. @Resource
  52. private ActiveMQUtils activeMQUtils;
  53. @Resource
  54. private RedisUtil redisUtil;
  55. final String MQ_KEY = "QG_MQ_MESSAGE";
  56. //发送
  57. @RequestMapping("/qg")
  58. public String qgActiveMQ(String userId,String goodsId){
  59. Message message = new Message();
  60. message.setUserId(userId);
  61. message.setGoodsId(goodsId);
  62. activeMQUtils.sendQueueMessage(MQ_KEY,message);
  63. return "用户"+userId+",排队中........";
  64. }
  65. //接收,60秒失效,JmsListener监听
  66. @JmsListener(destination =MQ_KEY)
  67. public void qg( Message message){
  68. String userId = message.getUserId();
  69. String goodsId = message.getGoodsId();
  70. String lockkey = "lock_goods_"+goodsId;
  71. while(!redisUtil.lock(lockkey,60L)){
  72. try {
  73. Thread.sleep(2000);
  74. } catch (InterruptedException e) {
  75. e.printStackTrace();
  76. }
  77. }
  78. String res = "";
  79. String flag = redisUtil.getStr(userId+":"+goodsId);
  80. if(flag!=null&&"1".equals(flag))
  81. {
  82. System.out.println("用户"+userId+"已经抢购过此商品!!!!");
  83. }else{
  84. String stock = redisUtil.getStr("goods_"+goodsId);
  85. int stockgoods = Integer.parseInt(stock);
  86. if(stockgoods>=1)
  87. {
  88. stockgoods = stockgoods - 1;
  89. redisUtil.setStr( "goods_"+goodsId,stockgoods+"");
  90. //添加用户购买记录
  91. redisUtil.setStr("qg:"+userId+":"+goodsId,"1");
  92. res = "用户"+userId+"抢到一个商品!!!";
  93. }else{
  94. res = "库存不足!用户"+userId+"没有抢到";
  95. }
  96. System.out.println(res);
  97. }
  98. redisUtil.unLock(lockkey);//解锁
  99. }
  100. }

13. 你的接口别人可以无条件访问吗?

https://blog.csdn.net/qq_34237136/article/details/84560692

不能。我们给每个用户设置了权限。用户只能访问有对应权限的方法。

用户在登陆成功之后,才可以去访问一些接口,否则其他的接口都是不可以访问状态,或者校验这个用户在发起请求的时候,是否是登陆状态,同时有些接口不需要登陆也可以访问。

首先,在看到这些需求的时候,要在配置文件里面进行配置白名单,之后读取白名单的配置文件获取到白名单的列表,这样就可以拿到了哪些接口不需要判断。

其次,要做一个拦截器,在每一次前台发起请求的时候,用来拦截,之后进行比较,如果是白名单接口,则不需要进行拦截,直接放掉,如果需要拦截,则进行拦截,进行业务判断。

在之后,根据业务逻辑,判断白名单,之后,判断登陆权限,在判断角色权限,最后抛出异常,返给前台,告知前台信息。

    1、读取白名单,以及设置拦截器

    2、根据业务进行处理。

14. 如果有人截取了token可以冒充用户吗

    这个其实是可以的,但是我们这边也做了相应的对策。我们在用户登录之后会记录他的ip并且保存,当用户访问其它接口时我们会对ip地址进行校验,如果前后两次ip不匹配并且距离跨度较大,我们会像qq一样提示用户登录异常,并且会使用短信验证以确保是用户本人操作。但是这个方法也有缺点,就是ip地址范围是有一定误差的,所以如果截取了token在一定区域内还是可以正常访问的。

15. 有用过Redis吗?

    有用过。主要是在做登录验证(token),鉴权、缓存数据还有分布式锁。缓存的话主要是一些常用的数据,比如说我们服务类型等,另外可能要进行频繁修改的数据,比如用户发布的订单等,这样可以避免频繁的对MySQL数据库进行操作。

16. 如果用户对一条订单进行了多次修改,那么数据库如何知道存哪条?

    首先我们设置了定时任务,会在每天晚上12点的时候将Redis数据库的内容写入到MySQL数据中,因为在MySQL数据库中每个用户都有唯一的ID,所以向数据库向MySQL数据库存入内容时,只需要判断存入数据是否有ID,有ID的是进行修改,没有ID的进行新增。

17. 你们数据库一张表有多少数据?有优化吗?

    阿里巴巴规范上说单表数据大概达到500或单表容量超过2G之后会严重影响性能,推荐进行分库分表。我们的数据量在100万左右。
    有做数据库的优化,我们想到了如果数据量到达一个足够高的情况该如何解决?所以我们进行了分库分表策略以保证性能,我们有垂直拆分和水平拆分以及主从同步,还有使用了Mycat中间件进行读写分离,Mycat里面有分片策略,其实就是水平拆分,而垂直拆分可以在Mycat中组成一张逻辑表,配置好后对开发人员来说其实是无感的。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注