java-springboot、mybatis、redis相关面试题

SpringBoot部分
相比Spring,Spring Boot有哪些优点
Springboot是一个基于spring的框架,对spring做了大量简化,使开发流程更快,更高效
它大量简化maven依赖,管理了大量的基础依赖
基于注解配置(JavaConfig),无需xml配置
内嵌Tomcat,部署流程简单
打包和部署更加灵活,允许独立运行
SpringBoot如何做全局异常处理
可以使用@ControllerAdvice注解,编写一个全局异常处理类,再自定义一个方法使用@ExceptionHandler来捕获具体的异常并作相应的处理
通常情况下后台向前台返回结果时,会把结果封装成包含有错误码,错误信息以及数据本身的json数据,因此我们可以使用自定义异常类,自定义枚举错误码,在捕获全局异常后,向前台返回一个包含错误码的信息
@SpringBootApplication注解的含义
@SpringBootApplication是SprnigBoot项目的核心注解,目的是开启自动配置,并表示该类为主启动类。它包含三个子标签
@ComponentScan注解:开启ioc自动扫描注解,默认扫描当前包及其子包中@Controller,@Service等,并把这些bean加载到ioc器中
@EnableAutoConfiguration注解:启用springboot自动配置,自动所有扫描classpath目录下面所有jar中的spring.factories文件实现配置类批量注册
@SpringBootConfiguration注解:标志该类为springboot配置类
spring-boot-starter-parent的作用
这是SpringBoot的父工程,它的作用是帮我们管理了很多的基础jar包,同时它继承了spring-boot-dependencies,在spring-boot-dependencies项目中通过管理了大量的依赖,同时通过维护了这些依赖的版本号
但是在项目中,还需要通过 去导入具体的依赖才能使用
spring-boot-starter-web的作用
此项目是Springboot和Springmvc整个的jar包,构建了web项目的基本环境,集成了日志,tomcat,springmvc,json支持等等
SpringBoot中如何读取配置
方式一:使用@Value读取配置文件
方式二:使用@ConfigurationProperties读取配置文件
SpringBoot中日志的level有哪些
日志级别从低到高分别为:
TRACE < DEBUG 如果设置为 WARN,则低于 WARN 的信息都不会输出
Spring中默认使用INFO级别输出到控制台
SpringBoot中如何管理事务
事务(transaction)是指业务逻辑上对数据库进行的一系列持久化操作,要么全部成功,要么全部失败。
在Springboot中,可以通过xml配置和注解配置
xml方式通过配置DataSourceTransactionManager和transactionManager实现
注解方式配置通过在主启动类上加上@EnableTransactionManagement开启事务管理器,在具体的实现层service类上加上@Transactional 实现事务
SpringBoot自动配置原理
在启动类上我们会打上: @SpringBootApplication 注解,它是一个组合标签,包括:
SpringBootConfuration ,本质是一个 Configuration ,代表Spring的配置类。
IOC自动扫描的注解 ,ComponentScan 会去扫描类上是否有:@Component ,@Respository ,@Service @Controller ,如果有,就会把这个类自动注册到Spring容器中。
EnableAutoConfiguration :就是启动SpringBoot自动配置的注解
在 @EnableAutoConfiguration 注解中,注册了一个选择器,其中有一个方法会去返回很多的自动配置的的全限定名,这些类会自动注册到Spring容器中,
那它是怎么去找到这些所谓的自动配置类的呢?
他会通过Spring的SPI接口,也就是通过一个SpringFactoryLoader去扫描 classpath中的所有的jar包中的 MET-INF/spring.factories 中的自动配置类,比如: DispatchServlert就对应了DispatchServlertAutoConfiguration自动配置类 , 它通过@Bean+方法的方式注册了一个 DispatchServlert 到Spring容器中了
SpringBoot启动流程
1.开启秒表计时
2.starting监听器,
3.处理应用参数
4.加载环境对象
5.打印横幅
6.创建Spring容器对象:AnnotationConfigApplicationContext
7.容器刷新的前置工作
8.刷新容器 ,这里会执行spring的ioc属性容器的refrsh方法,Bean的加载,初始化等都在这个里面,Tomcat的启动也在这个方法里面。
9.刷新容器后置工作
10.秒表停止
11.started事件
12.调用runner
13.running.listeners.
Mybatis部分
MyBatis中${}取值和#{}取值的区别
{}能够防止SQL注入,因为底层使用PreparedStatement对象,预编译,性能较高
${}不能防止SQL注入,因为底层使用Statement对象,不会预编译而是拼接字符串,性能较低
能使用#{}时尽量使用#{},如果需要动态传入表名或者字段名需要用 {}
MyBatis关联查询中,延迟加载和饥饿加载的区别
延迟加载,是先从单表查询,需要使用关联数据的时候才发起关联查询,不用的时候不查询关联的数据,又叫懒加载,饥饿加载,是在查询时将关联的数据立即查询出来加载进内存,不管用不用
MyBatis对象关联查询和集合关联查询怎么做
单个关联对象用associate ,适用于多对一的关联查询,使用javaType来定义实体类型,集合用collection,适用于一对多的关联查询,使用ofType来定义集合的泛型类型
MyBatis一级缓存和二级缓存的区别
缓存,是指将从数据库查询出的数据存放在缓存中,下次使用相同查询时不必再从数据库查询,而是直接从缓存中读取,从而减轻数据库查询的压力,提高性能
mybaits中的一级缓存,是SqlSession级别,默认开启,使用同一个SqlSession发送相同的SQL时命中;它的生命周期和SqlSession一致,当调用SqlSession.close()方法时会释放缓存
mybatis中的二级缓存,是namespace级别,默认不开启,执行同一个namespace的相同statement,发送相同的SQL时命中;它的生命周期是程序结束
当SQL中执行了update()、delete()、insert()操作,则缓存中的数据都会清空
MyBaits的Mapper接口没有实现类为社么可以用@Autowired直接注入
动态代理,赋值给mapper接口引用的对象其实是一个代理对象,这个代理对象是由 JDK 动态代理创建的。在解析mapper的时候,mybatis会通过java反射,获取到接口所有的方法
当调用接口中方法时,将通过接口全限定名+方法名对应找到映射文件中namespace和id匹配的sql,然后将执行结果返回
在MyBatis如何动态修改SQL
使用Mybatis的拦截器可以做到
MyBatis的动态SQL标签有哪些?
if标签:条件判断
choose、when、otherwise标签:选择结构,类似java中的switch
trim标签:对包含的内容加上前缀,后缀
where标签:主要是用来简化SQL语句中where条件判断的,能智能的处理and or,不必担心多余导致语法错误
foreach标签:遍历元素
Mybatis的mapper如何传递多个参数
方式一,可以使用map进行传参,SQL中使用map的key来引用取值
方式二,可以在SQL中使用#{param1},#{param2}...来引用取值,它是根据mapper接口对应方法中形参的顺序进行匹配的,不管接口方法的参数名字叫个啥,SQL都只能使用param1,param2,等来取值
方式三,可以使用@Param注解,给mapper接口方法的参数命名,在SQL中直接使用取的名字来引用
Mybatis,关联对象查询,使用嵌套子查询和JOIN连表有什么区别
嵌套子查询,指的是在查询一个主对象的时候,使用单表查询,在resultmap中额外发送一个子sql查询关联对象,然后映射给主对象
连表join查询,指的是查询一个主对象的时候,使用join连表的方式把主对象和关联对象的数据一次性查出来,用resultmap映射结果
他们的区别,join连表查询只发一条sql就能把数据查询出来,嵌套子查询会有一个n+1的问题,就是说如果主查询出来n条数据,那么会额外发送n条子sql去查询对应的关联对象,加上主查询那1次,也就是n+1次,因此它的性能相对较低的,一般我们会使用join连表查询
为什么要使用连接池
对数据库的操作都需要取得连接,使用完都需要关闭连接,如果每次操作需要打开关闭连接,这样系统性能很低下。连接池就可以动态的管理这些连接的申请,使用和释放,我们操作数据库只需要在连接池里获取连接,使用完放回连接池,这样大大节省了内存,提高效率。
数据库连接池的原理主要分为三部分
第一,连接池的建立,在系统初始化时建立几个连接对象以便使用。
第二,连接池的管理,客户请求连接数据库时,首先查看连接池中是否有空闲连接,如果有直接分配,如果没有就等待,直到超出最大等待时间,抛出异常
第三,连接池的关闭,当系统关闭时,连接池中所有连接关闭
Redis部分
讲一下你理解的Redis,为什么Redis很快
Redis是一种高性能的,开源的,C语言编写的非关系型数据库,可以对关系型数据库起到补充作用,同时支持持久化,可以将数据同步保存到磁盘
说Redis很快是相对于关系型数据库如mysql来说的,主要有以下因素
第一,数据结构简单,所以速度快
第二,直接在内存中读写数据,所以速度快
第三,采用多路IO复用模型,减少网络IO的时间消耗,避免大量的无用操作,所以速度快
第四,单线程避免了线程切换和上下文切换产生的消耗,所以速度快
你常用的Redis的数据存储结构有哪些,他们的使用场景分别是什么
Redis存储形式是键值对,支持value形式包括String,List,Set,ZSet,Hash。
String可以用作缓存,计数器,防攻击,验证码、登录过期等,List可以用来做队列,秒杀等,Set可以用来去重
Redis每种存储结构说 4 个命令吧
1.String
set key value 设置值
get key 取值
mset key value key value... 设置多个值
mget key key 获取多个值
incr key 将key中的值自增1
decre key 将key中的值自减1
2.List
lpush key value value... 从最左边设置值
rpush key value value... 从最右边设置值
lrange key start stop 查询key中指定区间的元素
lpop key 移出并返回key中最左边的元素
rpop key 移出并返回key中最右边的元素
3.Set
sadd key value value 添加元素
smembers key 返回集合key中的所有元素
srem key member 删除集合key中member元素
scard key 查询集合key中的元素数量
4.ZSet
zadd key score value (score value)... 添加元素
zcard key 查询集合key中元素数量
zcount key min max 返回有序集合key中score 在min和max之间的元素
zrange key start stop 返回有序集合key中索引在start和stop之间的元素
5.Hash
hset key field value 添加元素
hget key field 获取key集合中field键对应的值
hmset key field value (field value)... 添加元素并批量添加子键值对
hmget key field field 获取key集合中所有的子键值对
你们项目是怎么用Redis的
使用的是Springboot整合的redis,主要用来解决前后端分离后前后端会话问题,以及验证码的问题
怎么防止Redis宕机数据丢失问题
通过对Redis持久化,把内存中的数据和命令,保存一份到磁盘中做备份,当Redis发生宕机,重启服务器的时候,会从磁盘重新加载备份的数据,从而解决数据丢失问题
Redis持久化是什么?有几种方式
将内存中的数据备份到磁盘的过程,就叫作持久化
Redis持久化主要有两种方式,RDB和AOF,可以通过修改redis.conf进行配置
RDB是记录数据快照,而AOF是记录写命令的
Redis有了AOF持久化为什么还要RDB?
AOF和RDB各有所长
RDB是记录数据快照,它的优点是只产生一个持久化文件,体积相对较小,启动恢复速度快,备份方便,它的缺点是没办法做到数据百分百不丢失,因为它是每隔一定时间保存一次
AOF是记录写命令,它的优点是格式清晰,容易理解,数据更安全,采用append模式即使持久化过程中宕机,也不影响已经保存的数据,它的缺点是文件体积较大,恢复速度慢
根据实际需要来选择,通常二者可以结合来使用
Redis内存不够了怎么办?
方式一:增加物理内存
方式二:使用淘汰策略,删掉一些老旧数据
方式三:集群
你们Redis用在哪些业务上?用的什么存储结构
主要用做缓存,比如:验证码,分类缓存,数据字典缓存,权限数据缓存,登录信息缓存等。
String类型的存储结构用的比较多,并且使用了Json格式进行序列化。
淘汰策略有哪些?你们用的哪种
volatile-lru :从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集中任意选择数据淘汰
allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
allkeys-random:从数据集中任意选择数据淘汰
no-enviction:不使用淘汰
Redis事务和Mysql事务的区别
Mysql的事务是基于日志,记录修改数据前后的状态来实现的,而Redis的事务是基于队列实现的
Mysql中的事务满足原子性:即一组操作要么同时成功,要么同时失败,
Redis中的事务不满足原子性,即一组操作中某些命令执行失败了,其他操作不会回滚
因此对于比较重要的数据,应该存放在mysql中
使用Redis如何实现消息广播
Redis是使用发布订阅来实现广播的
订阅者通过 SUBSCRIBE channel命令订阅某个频道 , 发布者通过 PUBLISH channel message向该频道发布消息,该频道的所有订阅者都可以收到消息
为什么要使用Redis做缓存
一个字,快。
缓存它指的是将数据库的数据同步到内存中,客户端获取数据直接从内存中获取。由于内存读写速度大于磁盘,而使用缓存能减少磁盘读取,大大提高查询性能。
我们一般会将经常查询的,不会经常改变的热点数据,保存到缓存中,提高响应速度
缓存的执行流程
1.客户端发起查询请求
2.判断缓存中是否有数据
如果有,直接返回
如果没有,就从数据库查询,再把数据同步到缓存
3.返回数据给客户端
你们怎么保证Redis和Mysql的一致性
我们在代码中控制,如果数据库做是写操作,直接把redis中的对应数据删除,下次查询数据会重新写入缓存。
我们的业务对一致性要求不是很高,因此采用了先操作mysql,后删除redis。在写数据库和删除缓存行代码之间如果有查询请求依然会查询到Redis中的老数据,但是这种情况非常极端,而且我们的业务也能容忍这种短暂的脏数据。
我还知道其他方案,比如延迟双删 , 监听Mysql事务日志自动同步Redis等。
SpringCache常用注解
@EnableCaching:打在主启动类上,开启缓存功能
@Cacheable:打在方法上,表示该方法会开启缓存,打在类上,表示类中所有的方法都开启缓存,方法的返回值会自动写入缓存。如果缓存中已经有数据,方法将不会被调用,而是拿着缓存数据直接返回给客户端。
@CacheEvict:搭载类或者方法上,会将缓存清除
@CachePut:更新缓存
@Caching:组合操作,要应用于方法的多个缓存操作
@CacheConfig:打在类上,共享的一些常见缓存设置
了解缓存击穿,穿透,雪崩吗?怎么处理?
缓存击穿:缓存中没有,数据库中有的数据,由于某种原因比如缓存过期了,同时并发用户特别多,一时间都往数据库中读取数据
解决方案:加互斥锁,只能允许一个线程访问数据库,然后其他线程就可以往内存中拿
缓存穿透:客户端频繁请求一个缓存和数据库中都没有数据,导致数据库压力大。
解决方案:布隆过滤器来判断数据库中有没有这个key
缓存雪崩:缓存重启,或者大量key失效,导致大量并发打到数据库
解决方案:为key设置不同的过期时间
Redis的主从有什么优点,和缺点?
优点是读写分离,分担了读的压力,同时能起到备份作用,防止数据丢失
缺点是不能分担写的压力,主的单点故障没有解决,存储没有得到扩容
解释一下Redis的哨兵模式。哨兵的不足?
当主服务器中断服务后,可以将一个从服务器升级为主服务器 ,以便继续提供服务
哨兵就是用来监控主从服务器,实现故障恢复功能的。它会不断的检查主服务器和从服务器的健康状态,当某个服务器出现问题时,可以向管理员发起通知。如果主服务器不可用时,会自动选择一个从服务器作为新的主服务器,并让其他的从服务器从新的主服务器复制数据
哨兵也是主从模式,没有解决写的压力,只减轻了读的压力,而且存储也得不到扩容
Redis的cluster集群怎么存储数据的?
Redis Cluster集群采用哈希槽 (hash slot)的方式来分配的。它默认分配了16384个槽位,当我们set一个key 时,会用CRC16算法得到所属的槽位,然后将这个key 分到对应区间的节点上
什么情况下Redis集群不可用?
Redis Cluster有一个容错机制,如果半数以上的主节点与故障节点通信都超时了,就会认为该节点故障了,自动触发故障转移操作,故障节点对应的从节点升级为主节点。
但是如果某个主节点挂了,又没有从节点可以使用,那么整个Redis集群就不可用了、
Redis存储结构底层有没有了解?什么是SDS
简单动态字符串,是Redis自己封装的字符串结构。它记录了字节数组buf,字节数组中用到的字节数len,以及未使用的字节数free。
为了解决二进制安全问题,定义了len来表示已有字符串长度
为了防止缓冲区溢出,在分配内存的时候做了预留空间free
内存惰性释放,多余的内存加入free做预留,优化了内存频繁分配
针对不同的String长度定制了不同的SDS结构
Redis如何模拟队列和栈,用什么命令
list控制同一边进,同一边出就是栈;list控制一边进,另一边出就是队列
Redis存储单个对象怎么存,存储对象集合怎么存
单个对象可以使用String,也可以使用hash
集合对象可以使用hash,以便可以快速的通过field来取值
你们Redis用来做什么?使用的什么结构?
登录信息login,使用的是String结构存储
手机验证码code,使用的是String结构
课程分类course_type ,使用的是String结构
购物车保存,使用的是Hash结构
如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,
咱们下期见!答案获取方式:已赞 已评 已关~
学习更多JAVA知识与技巧,关注与私信博主(666)
【java-springboot、mybatis、redis相关面试题】java-springboot、mybatis、redis相关面试题
文章图片

    推荐阅读