黑马Java面试教程_P3_框架

系列博客目录


文章目录

  • 系列博客目录
  • 前言
  • 1.Spring
    • 1.1 Spring框架中的单例bean是线程安全的吗?
      • 面试文稿
    • 1.2 什么是AOP,你们项目中有没有使用到AOP?
    • Spring中的事务是如何实现的?
      • 总结
      • 面试文稿
    • 1.3 Spring中事务失效的场景有哪些
      • 总结
      • 面试文稿
    • 1.4 Spring的bean的生命周期
      • BeanDefinition
      • 总结
      • 面试文稿
    • 1.5 Spring中的循环引用
      • 总结
      • 面试文稿
  • 1.7 SpringMVC的执行流程知道嘛
      • 面试文稿
    • Springboot自动配置原理
      • 总结
      • 面试文稿
    • Spring框架常见注解(Spring、Springmvc、Springboot)
      • 面试文稿
    • MyBatis执行流程
      • 面试文稿
    • Mybatis是否支持延迟加载
      • 总结
      • 面试文稿
    • Mybatis的一级、二级缓存用过吗?
      • 一级缓存
      • 二级缓存
      • 注意事项
      • 总结
      • 面试文稿


前言

现在企业都是用框架进行开发,框架的面试题也很重要。spring的框架包含三个Spring、SpringMVB、SpringBoot。和持久层框架MyBatis。
在这里插入图片描述

1.Spring

1.1 Spring框架中的单例bean是线程安全的吗?

我们首先要知道 Spring框架中的bean是单例的吗?

@Service
@Scope("singleton")
public class UserServicelmpl implements UserService {
}
  • singleton:bean在每个SpringIOC容器中只有一个实例。
  • prototype:一个bean的定义可以有多个实例。

在这里插入图片描述

面试文稿

面试官:Spring框架中的单例bean是线程安全的吗?
候选人:嗯!不是线程安全的,是这样的,当多用户同时请求一个服务时,容器会给每一个请求分配一个线程,这时多个线程会并发执行该请求对应的业务逻辑(成员方法),如果该逻辑中有对该单列状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题。
Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。
比如:我们通常在项目中使用的Springbean都是不可改变的状态(比如Service类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。
如果你的bean有多种状态的话(比如 ViewModel对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用由“singleton"变更为“prototype”。

1.2 什么是AOP,你们项目中有没有使用到AOP?

考察你对AOP的理解,有没有使用AOP,因为AOP在Spring中是个难点。

AOP称为面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。

常见的AOP使用场景:

  • 记录操作日志 (因为很多地方都需要记录操作日志,所以代码是重复的,下面一点也是这个原因)
  • 缓存处理
  • Spring中内置的事务处理

下面详细解释一下如何使用AOP记录操作日:

记录操作日志思路:
获取请求的用户名、请求方式、访问地址、模块名称、登录ip、操作时间,记录到数据库的日志表中。
在这里插入图片描述

@Component
@Aspect   //切面类
public class SysAspect {@Pointcut("@annotation(com.itheima.annotation.Log)")//检测添加了Log注释的代码来使用下面的AOP代码。private void pointcut() {}@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {//获取用户名//需要通过解析seesion或token获取//获取被增强类和方法的信息Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;//获取被增强的方法对象Method method = methodSignature.getMethod();//从方法中解析注解if(method != null){Log logAnnotation = method.getAnnotation(Log.class);System.out.println(logAnnotation.name());}//方法名字String name = method.getName();System.out.println(name);//通过工具类获取Request对象RequestAttributes reqa =RequestContextHolder.getRequestAttributes();ServletRequestAttributes sra = (ServletRequestAttributes)reqa;HttpServletRequest request = sra.getRequest();//访问的urlString url = request.getRequestURI().toString();System.out.println(url);//请求方式String methodName = request.getMethod();System.out.println(methodName);//登录IPString ipAddr = getIpAddr(request);System.out.println(ipAddr);//操作时间System.out.println(new Date());*///保存到数据库(操作日志)//....return joinPoint.proceed();}
}

下面的代码加了Log注解,所以会调用使用AOP中的代码。
在这里插入图片描述
使用了AOP代码的输出结果如下。
在这里插入图片描述
下面就是在新增日志时候,使用AOP来记录操作日志的思路,AOP还可以用在很多功能中,只要添加了Log注释即可使用AOP的代码。
在这里插入图片描述

Spring中的事务是如何实现的?

Spring支持编程式事务管理和声明式事务管理两种方式。

  • 编程式事务控制:需使用TransactionTemplate来进行实现,对业务代码有侵入性,项目中很少使用
  • 声明式事务管理:声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

在这里插入图片描述
开始事务,需要在方法上添加@Transactional。(注意上面红字,出错也就是出现异常,后面内容需要使用这个逻辑)

总结

什么是AOP?
面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取公共模块复用,降低耦合。
你们项目中有没有使用到AOP?
记录操作日志,缓存,spring实现的事务。
核心是:使用aop中的环绕通知+切点表达式(找到要记录日志的方法)通过环绕通知的参数获取请求方法的参数(类、方法、注解、请求方式等),获取到这些参数以后,保存到数据库。
Spring中的事务是如何实现的?
其本质是通过AOP功能,对方法前后进行拦截,在执行方法之前开启事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

面试文稿

  1. 什么是AOP?
    候选人:AOP,即面向切面编程,在Spring中用于将那些与业务无关但对多个对象产生影响的公共行为和逻辑抽取出来,实现公共模块复用,降低耦合。常见的应用场景包括公共日志保存和事务处理。

  2. 你们项目中有没有使用到AOP?
    候选人:我们之前在后台管理系统中使用AOP来记录系统操作日志。主要思路是使用AOP的环绕通知和切点表达式,找到需要记录日志的方法,然后通过环绕通知的参数获取请求方法的参数,例如类信息、方法信息、注解、请求方式等,并将这些参数保存到数据库。

  3. Spring中的事务是如何实现的?
    候选人:Spring实现事务的本质是利用AOP完成的。它对方法前后进行拦截,在执行方法前开启事务,在执行完目标方法后根据执行情况提交或回滚事务。

1.3 Spring中事务失效的场景有哪些

主要考察 对spring框架的深入理解、复杂业务(更可能导致事务失效)的编码经验。

以下都可能会导致事务失效:

  • 异常捕获处理
  • 抛出检查异常
  • 非public方法

情况一:异常捕获处理
在这里插入图片描述
情况二:抛出检查异常
在这里插入图片描述

情况三:
在这里插入图片描述

总结

Spring中事务失效的场景有哪些

  • 异常捕获处理,自己处理了异常,没有抛出,解决:手动抛出
  • 抛出检查异常,配置rollbackFor属性为Exception
  • 非public方法导致的事务失效,改为public

面试文稿

  1. Spring中事务失效的场景有哪些?
    候选人:
    在项目中,我遇到过几种导致事务失效的场景:
    1. 如果方法内部捕获并处理了异常,没有将异常抛出,会导致事务失效。因此,处理异常后应该确保异常能够被抛出。
    2. 如果方法抛出检查型异常(checked exception),并且没有在@Transactional注解上配置rollbackFor属性为Exception,那么异常发生时事务可能不会回滚。
    3. 如果事务注解的方法不是公开(public)修饰的,也可能导致事务失效。

1.4 Spring的bean的生命周期

这个题比较难,难在bean加载过程中步骤很多,不好记忆。为什么问这个问题呢,不了解bean的生命周期,不影响开发,但是掌握了生命周期,可以帮助我们更好的掌握Spring的框架,更好的去理解 Spring容器是如何管理和创建bean实例。以后遇到bean的相关问题,比如spring的循环依赖问题,可以让我们更方便的调试和解决问题。

下面先从整体上介绍Bean创建的整个流程,再用代码的方式演示一边。

BeanDefinition

Spring容器在进行实例化时,会将xml配置的的信息封装成一个BeanDefinition对象,Spring根据BeanDefinition来创建Bean对象,里面有很多的属性用来描述Bean。

<bean id="userDao" class="com.itheima.dao.impl.UserDaolmpl" lazy-init="true"/>
<bean id="userService" class="com.itheima.service.UserServicelmpl" scope="singleton">
<property name="userDao" ref="userDao"></property></bean>

在这里插入图片描述

  • beanClassName:bean 的类名
  • initMethodName:初始化方法名称
  • properryValues:bean 的属性值
  • scope:作用域
  • lazyInit:延迟初始化

BeanDefinition首先使用Bean的构造函数来实例化Bean的对象,第二步是依赖注入,像一些Outwired表明的属性,第三步是Aware接口,实现接口就要实现里面的方法。
在这里插入图片描述
后置处理BeanPostProcessor可以对类实现增强。

package com.itheima.lifecycle;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;@Component
public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {public User() {System.out.println("User的构造方法执行了.........");}private String name ;@Value("张三")public void setName(String name) {System.out.println("setName方法执行了.........");}@Overridepublic void setBeanName(String name) {System.out.println("setBeanName方法执行了.........");}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("setBeanFactory方法执行了.........");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("setApplicationContext方法执行了........");}@PostConstructpublic void init() {System.out.println("init方法执行了.................");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("afterPropertiesSet方法执行了........");}@PreDestroypublic void destory() {System.out.println("destory方法执行了...............");}}
package com.itheima.lifecycle;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("user")) {System.out.println("postProcessBeforeInitialization方法执行了->user对象初始化方法前开始增强....");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("user")) {System.out.println("postProcessAfterInitialization->user对象初始化方法后开始增强....");//下面的代码开启(没有注释掉)则说明带有增强效果//cglib代理对象Enhancer enhancer = new Enhancer();//设置需要增强的类enhancer.setSuperclass(bean.getClass());//执行回调方法,增强方法enhancer.setCallback(new InvocationHandler() {@Overridepublic Object invoke(Object o, Method method, Object[] objects) throws Throwable {//执行目标方法return method.invoke(method,objects);}});//创建代理对象return enhancer.create();}return bean;}}

以下是配置代码:

@Configuration
@ComponentScan("com.itheima.lifecycle")
public class SpringConfig {
}

在这里插入图片描述
以下是测试代码:

package com.itheima.lifecycle;import com.itheima.config.SpringConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class UserTest {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);User user = ctx.getBean(User.class);System.out.println(user);}
}

测试结果如下:没有执行销毁方法,是因为没有关闭容器。销毁方法也不是重点。
在这里插入图片描述
通过打断点,可以看到user具体是什么类的对象。
未开启增强时
在这里插入图片描述
开启增强后,获得代理对象。
在这里插入图片描述

总结

在这里插入图片描述

面试文稿

Spring的bean的生命周期?

候选人:Spring中bean的生命周期包括以下步骤:

  1. 通过BeanDefinition获取bean的定义信息。
  2. 调用构造函数实例化bean。
  3. 进行bean的依赖注入,例如通过setter方法或@Autowired注解。
  4. 处理实现了Aware接口的bean。
  5. 执行BeanPostProcessor的前置处理器。
  6. 调用初始化方法,如实现了InitializingBean接口或自定义的init-method。
  7. 执行BeanPostProcessor的后置处理器,可能在这里产生代理对象。
  8. 最后是销毁bean。

1.5 Spring中的循环引用

在这里插入图片描述

有循环引用,可能会有死循环的问题。下面是否存在某对象,是指存在成品的对象,不能是半成品。
在这里插入图片描述

Spring解决循环依赖是通过三级缓存,对应的三级缓存如下所示

在这里插入图片描述
在这里插入图片描述
显然,一级缓存无法处理循环问题。
如果要想打破循环依赖,就需要一个中间人的参与,这个中间人就是二级缓存(下图中左边的圆柱体)。
在这里插入图片描述
但现在放入单例池中的A不是增强后的代理对象A。

如何解决这个问题呢?三级缓存。三级缓存帮我们存储对象工厂,帮助我们产生普通对象或者代理对象。
在这里插入图片描述
下图中最上面的是二级缓存。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
Spring使用三级缓存解决了大部分循环引用问题,但有些解决不了。
在这里插入图片描述
之前我们使用Setter方法注入,现在用构造器注入。Bean的生命周期第一步就是调用构造函数,三级缓存可以解决初始化(从依赖注入到BeanPostProcessor#after)中的循环依赖,不能解决构造函数中的循环依赖。使用加Lazy,延迟加载,什么时候需要Bean对象,我再进行Bean的创建,并不是实例化的时候直接把需要Bean对象注入注入进来。

为什么不能去除二级缓存,是因为要把对象工厂生成好的对象放在二级缓存里面,不能多次调用对象工厂让它再生成对象,它会产生多例,处理起来会很麻烦。

总结

  1. Spring中的循环引用
  • 循环依赖:循环依赖其实就是循环引用,也就是两个或两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于A
  • 循环依赖在spring中是允许存在,spring框架依据三级缓存已经解决了大部分的循环依赖
    ① 一级缓存:单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象
    ②二级缓存:缓存早期的bean对象(生命周期还没走完)
    ③ 三级缓存:缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的对象。
  1. 构造方法出现了循环依赖怎么解决?
    A依赖于B,B依赖于A,注入的方式是构造函数
    原因:由于bean的生命周期中构造函数是第一个执行的,spring框架并不能解决构造函数的的依赖注入
    解决方案:使用@Lazy进行懒加载,什么时候需要对象再进行bean对象的创建

面试文稿

  1. Spring中的循环引用?
    候选人:循环依赖发生在两个或两个以上的bean互相持有对方,形成闭环。Spring框架允许循环依赖存在,并通过三级缓存解决大部分循环依赖问题:

    1. 一级缓存:单例池,缓存已完成初始化的bean对象。
    2. 二级缓存:缓存尚未完成生命周期的早期bean对象。
    3. 三级缓存:缓存ObjectFactory,用于创建bean对象。
  2. 那具体解决流程清楚吗?
    候选人:解决循环依赖的流程如下:

    1. 实例化A对象,并创建ObjectFactory存入三级缓存。
    2. A在初始化时需要B对象,开始B的创建逻辑。
    3. B实例化完成,也创建ObjectFactory存入三级缓存。
    4. B需要注入A,通过三级缓存获取ObjectFactory生成A对象,存入二级缓存。
    5. B通过二级缓存获得A对象后,B创建成功,存入一级缓存。
    6. A对象初始化时,由于B已创建完成,可以直接注入B,A创建成功存入一级缓存。
    7. 清除二级缓存中的临时对象A。
  3. 构造方法出现了循环依赖怎么解决?
    候选人:由于构造函数是bean生命周期中最先执行的,Spring框架无法解决构造方法的循环依赖问题。可以使用@Lazy懒加载注解,延迟bean的创建直到实际需要时。

1.7 SpringMVC的执行流程知道嘛

Springmvc的执行流程是这个框架最核心的内容,一共有两种。

  • 视图阶段(老旧JSP等)
  • 前后端分离阶段(接口开发,异步)

第一种:视图阶段(JSP)
在这里插入图片描述

  1. 用户发送出请求到前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping(处理器映射器)
  3. HandlerMapping找到具体的处理器,生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet.
  4. DispatcherServlet调用HandlerAdapter(处理器适配器)
  5. HandlerAdapter经过适配调用具体的处理器(Handler/Controller)
  6. Controller执行完成返回ModelAndView对象
  7. HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)
  9. ViewReslover解析后返回具体View(视图)
  10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)
  11. DispatcherServlet响应用户

第二种:前后端分离阶段(接口开发、异步请求)
在这里插入图片描述

  1. 用户发送出请求到前端控制器DispatcherServlet
  2. DispatcherServet收到请求调用HandlerMapping(处理器映射器)
  3. HandlerMapping找到具体的处理器,生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。
  4. DispatcherServlet调用HandlerAdapter(处理器适配器)
  5. HandlerAdapter经过适配调用具体的处理器(Handler/Controller)
  6. 方法上添加了@ResponseBody
  7. 通过HttpMessageConverter来将返回结果转换为JSON并响应

面试文稿

SpringMVC的执行流程?
候选人:SpringMVC的执行流程包括以下步骤:

  1. 用户发送请求到前端控制器DispatcherServlet。
  2. DispatcherServlet调用HandlerMapping找到具体处理器。
  3. HandlerMapping返回处理器对象及拦截器(如果有)给DispatcherServlet。
  4. DispatcherServlet调用HandlerAdapter。
  5. HandlerAdapter适配并调用具体处理器(Controller)。
  6. Controller执行并返回ModelAndView对象。
  7. HandlerAdapter将ModelAndView返回给DispatcherServlet。
  8. DispatcherServlet传给ViewResolver进行视图解析。
  9. ViewResolver返回具体视图给DispatcherServlet。
  10. DispatcherServlet渲染视图并响应用户。

Springboot自动配置原理

Springboot中最高频的一道面试题,也是框架最核心的思想,问到SpringBoot,必问这道题。
在这里插入图片描述
三个注解中最重要的是EnableAutoConfiguration,下面详细介绍一下。
@Import就是导入一些类,把他们放到Spring容器中。
在这里插入图片描述
右下角有默认提供的一百多个自动配置类,但这些并不是都进行加载,比如打开一个进行查看。
在这里插入图片描述
通过@ConditionalOnClass判断是否有对应class,来进行是否加载下面的public class RedisAutoConfiguration。@Bean,就是把下面方法的返回值放入到Spring容器中,也就是会有个RedisTemplate型的东西放入到了Spring容器中,@ConditionalOnMissingBean是来判断当前容器中是否有对应的Bean,如果有,就不走下面的代码了(已经有了就不用再创建了)。

总结

Springboot自动配置原理
1、在Spring Boot项目中的引导类上有一个注解@SpringBootApplication,这个注解是对三个注解进行了封装,分别是:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

2、其中@EnableAutoConfiguration是实现自动化配置的核心注解。该注解通过@Import注解导入对应的配置选择器。内部就是读取了该项目和该项目引用的Jar包的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。
3、条件判断会有像@ConditionalOnClass这样的注解,判断是否有对应的class(字节码)文件,如果有则加载该类,把这个配置类的所有的Bean放入spring容器中使用。

面试文稿

Springboot自动配置原理?

候选人:Spring Boot的自动配置原理基于@SpringBootApplication注解,它封装了@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan。@EnableAutoConfiguration是核心,它通过@Import导入配置选择器,读取META-INF/spring.factories文件中的类名,根据条件注解决定是否将配置类中的Bean导入到Spring容器中。

Spring框架常见注解(Spring、Springmvc、Springboot)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

面试文稿

谈到注解,主要讲Spring中请求和相应的注解,SpringMVC中注入的注解,SpringBoot中自动装配的注解。注意不要混淆着去说。

  1. Spring 的常见注解有哪些?
    候选人:Spring的常见注解包括:

    • 声明Bean的注解:@Component、@Service、@Repository、@Controller。
    • 依赖注入相关注解:@Autowired、@Qualifier、@Resource。
    • 设置作用域的注解:@Scope。
    • 配置相关注解:@Configuration、@ComponentScan、@Bean。
    • AOP相关注解:@Aspect、@Before、@After、@Around、@Pointcut。
  2. SpringMVC常见的注解有哪些?
    候选人:SpringMVC的常见注解有:

    • @RequestMapping:映射请求路径。
    • @RequestBody:接收HTTP请求的JSON数据。
    • @RequestParam:指定请求参数名称。
    • @PathVariable:从请求路径中获取参数。
    • @ResponseBody:将Controller方法返回的对象转化为JSON。
    • @RequestHeader:获取请求头数据。
    • @PostMapping、@GetMapping等。
  3. Springboot常见注解有哪些?
    候选人:Spring Boot的常见注解包括:

    • @SpringBootApplication:由@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan组成。
    • 其他注解如@RestController、@GetMapping、@PostMapping等,用于简化Spring MVC的配置。

MyBatis执行流程

了解执行流程可以更好的:

  • 理解了各个组件的关系
  • Sql的执行过程(参数映射、sql解析、执行和结果处理)

在这里插入图片描述
有了配置文件,再用sqlsession来操作数据库。
在这里插入图片描述
在这里插入图片描述
mappedStatement对象就是用来封装某一个标签的,也就是一次数据库操作。
在这里插入图片描述

面试文稿

MyBatis执行流程?

候选人:MyBatis的执行流程如下:

  1. 读取MyBatis配置文件mybatis-config.xml。
  2. 构造会话工厂SqlSessionFactory。
  3. 会话工厂创建SqlSession对象。
  4. 操作数据库的接口,Executor执行器。
  5. Executor执行方法中的MappedStatement参数。
  6. 输入参数映射。
  7. 输出结果映射。

Mybatis是否支持延迟加载

Mybatis支持延迟记载,但默认没有开启。什么叫做延迟加载?
在这里插入图片描述
延迟加载原理

  1. 使用CGLIB创建目标对象的代理对象
  2. 当调用目标方法user.getOrderlist()时,进入拦截器invoke方法,发现user.getOrderlist()是nul值,执行sal查询order列表
  3. 把order查询上来,然后调用user.setOrderList(ListorderList),接着完成user.getOrderList()方法的调用

在这里插入图片描述

总结

在这里插入图片描述

面试文稿

  1. Mybatis是否支持延迟加载?

    候选人:MyBatis支持延迟加载,即在需要用到数据时才加载。可以通过配置文件中的lazyLoadingEnabled配置启用或禁用延迟加载。

  2. 延迟加载的底层原理知道吗?
    候选人:延迟加载的底层原理主要使用CGLIB动态代理实现:

    1. 使用CGLIB创建目标对象的代理对象。
    2. 调用目标方法时,如果发现是null值,则执行SQL查询。
    3. 获取数据后,设置属性值并继续查询目标方法。

Mybatis的一级、二级缓存用过吗?

下图是一般的缓存的思路,一级、二级缓存的思路与下面基本相同。
在这里插入图片描述
本地缓存,基于PerpetualCache类,本质是一个HashMap。下面两个都基于本地缓存来做的缓存。

  • 一级缓存:作用域是session级别(SqlSession,范围相对较小)
  • 二级缓存:作用域是namespace和mapper的作用域,不依赖于session(SqlSession)。

一级缓存

一级缓存:基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当Session进行flush或close之后,该Session中的所有Cache就将清空,默认打开一级缓存。
在这里插入图片描述
上面图中代码,只用了一个SqlSession。但是要是用来两个SqlSession,那就要执行两次查询。

二级缓存

二级缓存是基于namespace和mapper的作用域起作用的,不是依赖于SQLsession,默认也是采用 PerpetualCache类,
HashMap 存储。
在这里插入图片描述
如何只执行一次SQL呢,开启二级缓存。
在这里插入图片描述

注意事项

  1. 对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了新增、修改、删除操作后,默认该
    作用域下所有 select 中的缓存将被 clear
  2. 二级缓存需要缓存的数据实现Serializable接口
  3. 只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中

总结

在这里插入图片描述

面试文稿

  1. Mybatis的一级、二级缓存用过吗?
    候选人:MyBatis的一级缓存是基于PerpetualCache的HashMap本地缓存,作用域为Session,默认开启。二级缓存需要单独开启,作用域为Namespace或mapper,默认也是采用PerpetualCache,HashMap存储。

  2. Mybatis的二级缓存什么时候会清理缓存中的数据?
    候选人:当作用域(一级缓存Session/二级缓存Namespaces)进行了新增、修改、删除操作后,默认该作用域下所有select中的缓存将被清空。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/891402.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VK11\VK12保存增强

VK11\VK12保存增强 一、 VK11\VK12保存增强 事务码VK11、VK12创建和修改条件记录时&#xff0c;点击保存时修改其中的条件 二、增强步骤 通过查找&#xff0c;对应的BADI&#xff1a;SD_COND_SAVE_A 通过SE19创建BADI&#xff1a;ZSD_COND_SAVE_A修改函数CONDITION_SAVE_E…

使用pandas把数据库中的数据转成csv文件

使用pandas把数据库中的数据转成csv文件 1、效果图 2、流程 1、连接数据库,获取数据 2、把一些中文字符转成gbk,忽略掉无法转化的 3、把数据转成csv 3、代码 import pymysql import pandas as pddef get_database(databasename):

急需升级,D-Link 路由器漏洞被僵尸网络广泛用于 DDoS 攻击

僵尸网络活动增加 &#xff1a;新的“FICORA”和“CAPSAICIN”僵尸网络&#xff08;Mirai 和 Kaiten 的变体&#xff09;的活动激增。 被利用的漏洞 &#xff1a;攻击者利用已知的 D-Link 路由器漏洞&#xff08;例如 CVE-2015-2051、CVE-2024-33112&#xff09;来执行恶意命…

Linux SVN下载安装配置客户端

参考&#xff1a; linux下svn服务器搭建及使用&#xff08;包含图解&#xff09;_小乌龟svn新建用户名和密码-CSDN博客 1.ubuntu安装svn客户端 “subversion” sudo apt-get update sudo apt-get install subversion 查看安装的版本信息&#xff0c;同时看是否安装成功 s…

MM-2024 | 智能体遇山开路,遇水架桥! ObVLN:突破障碍,受阻环境中的视觉语言导航

作者&#xff1a;Haodong Hong, Sen Wang, Zi Huang 单位&#xff1a;昆士兰大学 论文链接&#xff1a;Navigating Beyond Instructions: Vision-and-Language Navigation in Obstructed Environments (https://dl.acm.org/doi/pdf/10.1145/3664647.3681640) 代码链接&#…

远程命令执行之基本介绍

一.远程命令执行漏洞 1.命令执行 命令执行是指计算机程序接受用户输入的命令&#xff0c;并按照命令的要求执行相应的操作。命令可以执行各种操作&#xff0c;例如读取文件、创建文件、修改文件、运行程序、删除文件等。 命令执行通常是通过一个命令行界面或终端窗口进行的。在…

ReactiveStreams、Reactor、SpringWebFlux

注意&#xff1a; 本文内容于 2024-12-28 21:22:12 创建&#xff0c;可能不会在此平台上进行更新。如果您希望查看最新版本或更多相关内容&#xff0c;请访问原文地址&#xff1a;ReactiveStreams、Reactor、SpringWebFlux。感谢您的关注与支持&#xff01; ReactiveStreams是…

Android笔试面试题AI答之Android基础(8)

Android入门请看《Android应用开发项目式教程》&#xff0c;视频、源码、答疑&#xff0c;手把手教 文章目录 1.Android新建工程需要注意的地方有哪些&#xff1f;**1. 选择合适的项目模板****2. 配置项目基本信息****3. 选择最低 SDK 版本****4. 配置构建工具****5. 选择编程…

【阻塞队列】- ArrayBlockingQueue 的原理-迭代器

文章目录 1. 前言2. 迭代器3. Itrs3.1 参数3.2 迭代器 Itr3.2.1 参数3.2.2 构造器3.2.3 hasNext3.2.4 next3.2.5 remove3.2.6 shutdown3.2.7 removedAt3.2.8 takeIndexWrapped 3.3 doSomeSweeping&#xff08;tryHandler&#xff09;3.4 register3.5 takeIndexWrapped3.6 remov…

ARM 汇编基础总结

GNU 汇编语法 编写汇编的过程中&#xff0c;其指令、寄存器名等可以全部使用大写&#xff0c;也可以全部使用小写&#xff0c;但是不能大小写混用。 1. 汇编语句的格式 label: instruction comment label即标号&#xff0c;表示地址位置&#xff0c;有些指令前面可能会有标…

【MySQL】深度学习数据库开发技术:使用CC++语言访问数据库

**前言&#xff1a;**本节内容介绍使用C/C访问数据库&#xff0c; 包括对数据库的增删查改操作。 主要是学习一些接口的调用&#xff0c; 废话不多说&#xff0c; 开始我们的学习吧&#xff01; ps:本节内容比较容易&#xff0c; 友友们放心观看哦&#xff01; 目录 准备mysql…

华为配置 之 RIP

简介&#xff1a; RIP&#xff08;路由信息协议&#xff09;是一种广泛使用的内部网关协议&#xff0c;基于距离向量算法来决定路径。它通过向全网广播路由控制信息来动态交换网络拓扑信息&#xff0c;从而计算出最佳路由路径。RIP易于配置和理解&#xff0c;非常适用于小型网络…

1.GPU简介及英伟达开发环境配置

前言 This book shows how, by harnessing the power of your computer’s graphics process unit (GPU), you can write high-performance software for a wide rangeof applications.Although originally designed to render computer graphics ona monitor (and still used…

电脑cxcore100.dll丢失怎么办?

电脑运行时常见问题解析&#xff1a;应对DLL文件丢失、文件损坏与系统报错的实用指南 在数字时代&#xff0c;电脑已成为我们工作、学习和娱乐不可或缺的工具。然而&#xff0c;正如任何精密机械都可能遇到故障&#xff0c;电脑在运行过程中也难免会遇到各种问题&#xff0c;如…

【无线传感网】时间同步技术

文章目录 时间同步模型时钟模型1. 节点本地时钟模型2. 节点逻辑时钟模型 通信模型1. 单向报文传递2. 双向报文交换3. 广播参考报文4. 参数拟合技术 时钟同步的误差来源 时间同步协议时钟同步的类别1. 时钟速率同步与偏移同步2. 同步期限&#xff1a;长期同步与按需同步3. 同步范…

C# 实用工具分享(1)

大家好&#xff0c;今天分享一些在开发过程中比较实用的工具。 首先在软件开发的过程中不可避免的要使用截图这样的功能&#xff0c;以前这样的功能我自己也是选择开发出新功能。但是自己开发还是非常费时费力的&#xff0c;并且效果也不一定特别好。 于是我找到了一个现成的…

积分图(Integral Image)与均值滤波的快速实现

积分图&#xff08;Integral Image&#xff09;也称为求和图&#xff08;Summed Area Table&#xff09;&#xff0c;是一种用于快速计算图像中任意矩形区域像素值总和的技术。 基本概念 积分图的每个位置(i, j)存储的是从图像左上角(1, 1)到当前位置(i, j)所有像素值的累积和…

curl+openssl 踩坑笔记

curl编译&#xff1a;点击跳转 踩坑一 * SSL certificate problem: unable to get local issuer certificate * closing connection #0 curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.se/docs/sslcerts.html …

[AI] 深度学习的“黑箱”探索:从解释性到透明性

目录 1. 深度学习的“黑箱”问题&#xff1a;何为不可解释&#xff1f; 1.1 为什么“黑箱”问题存在&#xff1f; 2. 可解释性研究的现状 2.1 模型解释的方法 2.1.1 后置可解释性方法&#xff08;Post-hoc Explanations&#xff09; 2.1.2 内在可解释性方法&#xff08;I…

python-Flask:SQLite数据库路径不正确但是成功访问到了数据库,并对表进行了操作

出现了这个问题&#xff0c;就好像是我要去找在南方的人&#xff0c;然后我刚好不分南北&#xff0c;我认为的方向错了&#xff0c;实则方向对了。 在我针对复盘解决&#xff1a;sqlite3.OperationalError: unrecognized token: “{“-CSDN博客这个内容的时候&#xff0c;又出现…