java-SSM框架

java-SSM框架

SSM–Spring, Spring MVC, MyBatis

SpringIOC

什么是AOP?

AOP是面向切面编程,在spring中用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取公共模块复用,降低耦合,一般比如可以做为公共日志保存,事务处理等

补充: AOP使用场景–记录操作日志, 缓存处理, Spring中内置的事务处理

你们项目中有没有使用到AOP

我们当时在后台管理系统中,就是使用AOP来记录了系统的操作日志
主要思路是这样的,使用AOP中的环绕通知+切点表达式,这个表达式就是要找到要记录日志的方法,然后通过环绕通知的参数获取请求方法的参数,比如类信息、方法信息、注解、请求方式等,获取到这些参数以后,保存到数据库

具体如何使用AOP

image.png

Spring中的事务是如何实现的

spring实现的事务本质就是AOP完成,对方法前后进行拦截,在执行方法之前开启事务,在执行完目标方法之后根据执行情况提交或者回滚事务。–(声明式事务管理)

补充:
编程式事务管理(需要使用TransactionTemolate实现,对业务代码有侵入性,很少使用)和声明式事务管理

Spring中如何管理事务?

通过在类或方法上加@Transactional注解方式来管理事务

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

image.png
嗯!这个在项目中之前遇到过,我想想啊
第一个,如果方法上异常捕获处理,自己处理了异常,没有抛出,就会导致事务失效,所以一般处理了异常以后,别忘了抛出去就行了

解决方法–在catch中添加throw new RuntimeException(e)抛出

image.png
第二个,如果方法抛出检查异常,如果报错也会导致事务失效(Spring默认只会回滚非检查异常),最后在spring事务的注解上,就是@Transactional上配置rollbackFor属性为Exception,这样不管是什么异常,都会回滚事务(@Transaction(roolbackFor=Exception.class))
image.png
第三,我之前还遇到过一个,如果方法上不是public修饰的,也会导致事务失效(Spring为方法创建代理,添加事务通知,前提条件都是该方法是public的)
嗯,就能想起来那么多

Spring事务的传播行为有哪些?

PROPAGATION_REQUIRED
表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运
行,否则的话重新开启一个事务。(如果被调用端发生异常,那
么调用端和被调用端事务都将回滚)
PROPAGATION_REQUIRES_NEW
总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
PROPAGATION_SUPPORTS
表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行
PROPAGATION MANDATORY
表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
PROPAGATION_NOT_SUPPORTED
总是非事务地执行,并挂起任何存在的事务。
PROPAGATION NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常
PROPAGATION_NESTED
表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封
装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,
内层事务并不影响外层事务。如果封装事务不存在,则同propagation.required的一样

什么是ICO和DI

ICO–控制反转
将创建及管理对象的权利交给Spring容器,对象的创建控制权由程序自身转移到外部(容器)
DI–依赖注入
是ICO的一种实现方式, 对象的依赖关系由外部容器在创建对象时注入,而不是由对象自己创建和管理。这样做的好处是,对象之间的依赖关系更加松耦合,易于测试和维护。通过依赖注入,我们可以将对象的依赖关系从代码中解耦出来,使得代码更加简洁和可扩展

Spring Bean有哪些配置方法?

  1. XML方式–在XML配置文件中,通过标签配置bean对象–使用元素定义Bean的属性和依赖关系
  2. 注解方式

–通过@Configuration+@Bean方式配置对象
–通过@Conponent @Controller @Service @Repository配置bean
–通过@ComponetScan(“扫描包名”)管理bean

Spring Bean的作用域有哪些?默认是那种?

默认–单例 singleton
bean作用域–singleton单例
prototype多例
如果是Web项目: request session globalSession
Spring Bean的作用域决定了Bean实例的生命周期和可见范围。

  1. singleton:默认,每个容器中只有⼀个bean的实例,单例的模式由BeanFactory自身来维护。该对象的生命周期是与Spring IOC容器⼀致的(但在第⼀次被注⼊时才会创建)
  2. prototype:为每⼀个bean请求提供⼀个实例。在每次注⼊时都会创建⼀个新的对象
  3. request:bean被定义为在每个HTTP请求中创建⼀个单例对象,也就是说在单个请求中都会复用这⼀个单例对象
  4. session:与request范围类似,确保每个session中有⼀个bean的实例,在session过期后,bean会随之失效
  5. application:bean被定义为在ServletContext的生命周期中复用⼀个单例对象
  6. websocket:bean被定义为在websocket的⽣命周期中复用⼀个单例对象
  7. global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同

Spring Bean依赖注入(DI)的方式有哪些?

setter注入–通过set方法注入依赖的bean
构造器注入–通过构造方法注入依赖的bean
注解注入–通过@Autowired或@Resource注入依赖的bean

Spring中常用的注解有哪些?

image.png

是否了解容器初始化流程(IOC原理)

1.创建配置
基于xml或基于注解配置SpringBean
2.配置解析
读取xml内容,并得到一个Document对象解析Document对象,遍历bean标签的节点将每一个Bean标签封装到一个BeanDefinition对象
3.注册bean定义到容器中
将bean的定义对象存储到容器中的map集合中
map集合:在容器的核心实现类DefaultListableBeanFactory中,COncurrentHashMap以bean标签中配置的id作为key以beanDefinition对象作为value存储到map集合中
4.初始化所有单列对象
完成注册后,查看所有注册bean定义,如果是非抽象,并且不是懒加载的单例对象会被立刻创建,创建出来的单例对象会存储到singletonObjects map集合也是一个COncurrentHashMap

是否了解容器getBean流程(IOC原理)

IOC容器getBean流程
1.判断单例map集合中是否已经创建该对象
有返回
没有下一流程
2.判断是否存在父容器,且父容器是否包含该对象
包含:调用父容器的getBean
没有下一流程
3.准备尝试创建对象,beanDefinitionMap中获取bean定义
没有抛出NoSuchBeanDefinition
有下一流程
4.判断bean定义的scope属性
单例
调用createBean创建对象
加入单例map集合
多例
调用createBean创建对象
其它
5.createBean创建对象
获取要创建bean的class
判断是否使用工厂方法创建对象
调用工厂方法创建对象
运行到这里说明是使用构造器创建
根据构造器参数的个数、类型
确定到底使用哪个构造器创建
使用JDK反射方法创建对象
6.依赖注入
调用populateBean方法进行依赖注入

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

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

补充:
image.png
成员方法需要考虑线程安全

在Spring框架中,默认情况下,单例(Singleton)的Bean是线程安全的。当一个Bean被定义为单例时,Spring容器会在启动时创建一个实例,并在整个应用程序的生命周期中共享该实例。
由于单例Bean是共享的,多个线程可能同时访问同一个实例。为了确保线程安全,Spring采用了一些机制来保证单例Bean的线程安全性:
1. 状态无关性:Spring鼓励将单例Bean设计为无状态的,即不包含可变的实例变量。这样可以避免多个线程之间共享状态造成的竞争条件。
2. 依赖注入:Spring通过依赖注入来管理Bean之间的依赖关系。每个线程都会获得一个独立的Bean实例,避免了多个线程之间共享Bean实例造成的竞争条件。
尽管Spring的单例Bean是线程安全的,但仍然需要注意以下几点:
1. 避免在单例Bean中使用可变的实例变量,或者确保对可变变量的访问是线程安全的。
2. 尽量避免在单例Bean中使用线程不安全的第三方库或组件。
3. 如果需要在单例Bean中处理线程安全的逻辑,可以使用同步机制(如synchronized关键字)来保证线程安全。
总而言之,Spring框架中的单例Bean是线程安全的,但在编写和使用单例Bean时,仍然需要注意线程安全性,并遵循相关的最佳实践。

是否了解Spring同名bean的覆盖问题

默认情况:同一个配置文件中出现id相同的bean会报错,不同的配置文件出现id相同的bean后加载的bean会
将先加载的bean覆盖掉称为bean的覆盖
bean的覆盖不会报错,但可能影响我们的项目,可以通过属性设置不允许bean的覆盖``
allowBeanDefinitionOverriding设置为false

Spring的Bean的生命周期

嗯!,这个步骤还是挺多的,我之前看过一些源码,它大概流程是这样的
首先会通过BeanDefinition获取bean的定义信息,这里面就封装了bean的所有信息,比如,类的全路径,是否是延迟加载,是否是单例等等这些信息
在创建bean的时候,
第一步是调用构造函数实例化bean
第二步是bean的依赖注入,比如一些set方法注入,像平时开发用的@Autowire都是这一步完成
第三步是处理Aware接口,(Aware结尾的接口:BeanNameAware, BeanFactoryAware, ApplicationContextAware), 如果某一个bean实现了Aware接口就会重写方法执行
第四步是bean的后置处理器BeanPostProcessor
第五步是初始化方法,比如实现了接口InitializingBean或者自定义了方法init-method标签或@PostContruct
第六步是执行了bean的后置处理器BeanPostProcessor,主要是对bean进行增强,有可能在这里产生代理对象
最后一步是销毁bean
image.png

Spring中的循环依赖

嗯,好的,我来解释一下
循环依赖:循环依赖其实就是循环引用,也就是两个或两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于A
循环依赖在spring中是允许存在,spring框架依据三级缓存已经解决了大部分的循环依赖
①一级缓存:单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象

作用: 限制bean在beanFactory中只存一份,即实现singleton scope,解决不了循环依赖

②二级缓存:缓存早期的bean对象(生命周期还没走完)
③三级缓存:缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的
image.png
image.png

那具体解决流程清楚吗?

第一,先实例A对象,同时会创建ObjectFactory对象存入三级缓存singletonFactories
第二,A在初始化的时候需要B对象,这个走B的创建的逻辑
第三,B实例化完成,也会创建ObjectFactory对象存入三级缓存singletonFactories
第四,B需要注入A,通过三级缓存中获取ObjectFactory来生成一个A的对象同时存入二级缓存,这个是有两种情况,一个是可能是A的普通对象,另外一个是A的代理对象,都可以让ObjectFactory来生产对应的对象,这也是三级缓存的关键
第五,B通过从通过二级缓存earlySingletonObjects 获得到A的对象后可以正常注入,B创建成功,存入一级缓存singletonObjects
第六,回到A对象初始化,因为B对象已经创建完成,则可以直接注入B,A创建成功存入一次缓存singletonObjects
第七,二级缓存中的临时对象A清除

:::info
①一级缓存:单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象
:::
:::info
②二级缓存:缓存早期的bean对象(生命周期还没走完)
:::
:::info
③三级缓存:缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的
:::
:::info
流程:

  1. 实例化A,同时创建ObjectFactory对象存入三级缓存
  2. A初始化时需要B,所以要创建B
  3. B实例化完成后,也会创建ObjectFactory对象存入三级缓存
  4. B需要注入A,通过三级缓存中获取ObjectFactory生成A的对象同时存入二级缓存,分为两种情况–1是A的普通对象,2 是A的代理对象,都可以让ObjectFactory生成对应的对象
  5. B通过二级缓存获取A的对象后直接注入,B创建成功,存入一级缓存
  6. 回到A对象初始化,直接注入B,A创建成功存入一级缓存
  7. 二级缓存清除临时对象A
    :::

构造方法出现了循环依赖怎么解决?

由于bean的生命周期中构造函数是第一个执行的,spring框架并不能解决构造函数的的依赖注入,可以使用@Lazy懒加载,什么时候需要对象再进行bean对象的创建
image.png

SpringMVC

image.png

SpringMVC的执行流程知道嘛

嗯,这个知道的,它分了好多步骤

  1. 用户发送出请求到前端控制器DispatcherServlet,这是一个调度中心
  2. DispatcherServlet收到请求调用HandlerMapping(处理器映射器)
  3. HandlerMapping找到具体的处理器(可查找xml配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给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响应用户

当然现在的开发,基本都是前后端分离的开发的,并没有视图这些,一般都是handler中使用Response直接结果返回

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

Snipaste_2023-10-13_10-56-43.png
Snipaste_2023-10-13_10-57-04.png

SpringMVC接收参数的注解?

@RequestBody–接收json参数
@RequestParam–接收表单参数 key=value形式参数
@PathCariable–获取路劲参数

Filter,Interceptor,AOP的区别

AOP使用的主要是动态代理,
过滤器使用的主要是函数回调;
拦截器使用是反射机制。
一个请求过来,先进行过滤器处理,看程序是否受理该请求。过滤器放过后程序中的拦截器进行处理,处理
完后进入被AOP动态代理重新编译过的主要业务类进行处理。
Filter:和框架无关,可以控制最初的http请求,但是更细一点的类和方法控制不了。
Interceptor:可以控制请求的控制器和方法,但控制不了请求方法里的参数(用于处理页面提交的请求响应并
进行处理,例如做国际化,做主题更换,过滤等)。
Aspect:可以自定义切入的点,有方法的参数,但是拿不到http请求,可以通过其他方式如
RequestContextHolder获得。
都可以实现权限检查,日志记录。不同的是使用的范围不同,规范不同,深度不同。

SpringBoot

SpringBoot自动装配原理是什么?

嗯,好的,它是这样的。
在Spring Boot项目中的引导类上有一个注解@SpringBootApplication,这个注解是对三个注解进行了封装,分别是:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan

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

Spring Boot的自动配置原理是通过条件注解和自动配置类实现的。条件注解用于判断是否需要自动配置某个组件,自动配置类则定义了一系列的@Bean方法来自动配置相关组件。Spring Boot在启动时会自动扫描并创建这些自动配置类,从而实现自动配置的功能。同时,用户也可以通过自定义配置来对自动配置进行定制。

Spring和SpringBoot的区别

本质上使用的是动态代理的机制,即底层使用的是反射技术,通过mybatis生成具有访问数据库能力的具体实现类来实现:当获取到mapper接口类型的实例时,实际上获取到的是mybatis生成的代理类对象;当调用mapper接口的方法时,代理类会拦截这个方法的调用,并根据方法名找到xxxMapper.xml里的sql语句,再接着执行数据库并将结果返回给调用方

SpringBoot你使用过哪些常见starter?

  • springboot-starter-web
  • springboot-starter-jdbc
  • springboot-starter-amqp
  • springboot-starter-data-redis

SpringBoot的配置文件有哪些?优先级是怎样的?

application.properties/yml
bootstrap.properties/yml
加载顺序–bootstrap.properties->bootstrap.yml->application.properties->application.yml

SpringBoot中如何读取自定义的配置?

@Value
@ConfigurationProperties(profix="xxl.job)

SprIngBoot热启动

spring-boot-starter-devtools

SpringBoot如何配置多环境?

如果所有环境配置都写到一个配置文件中,不好维护可以定义多个环境配置文件的方式来实现:
如:application-{环境名称}.yml
application-dev.yml
application-test.yml
application-prod.yml
spring:
profiles:
active:prod激活生产环境的配置

SpringBoot Run方法运行原理(高手)

SpringApplication的run方法的实现是启动原理探寻的起点,该方法的主要流程大体可以归纳如下:
1、如果我们使用的是SpringApplication的静态run方法,那么,这个方法里面首先要创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的实例方法。在SpringApplication实例初始化的时候,它会提前做几件事情:
根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用ApplicationContextlnitializer。
使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener。
推断并设置main方法的定义类。
2、SpringApplication实例初始化完成并且完成设置后,就开始执行run方法的逻辑了,方法执行依次,首先遍历执行所有通过SpringFactoriesLoader可以查找到并加载的SpringApplicationRunListener。调用它们的started()方法,告诉这些SpringApplicationRunListener,“嘿,SpringBoot应用要开始执行咯!”。
3、创建并配置当前SpringBoot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile)。
4、遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”
5、如果SpringApplication的showBanner属性被设置为true,则打印banner。
6、根据用户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,当然,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用。
7、ApplicationContext创建好之后,SpringApplication会再次借助Spring-FactoriesLoader,查找并加载classpath中所有可用的ApplicationContext-Initializer,然后遍历调用这些ApplicationContextlnitializer的initialize(applicationContext)方法来对已经创建好的ApplicationContext进行进一步的处理。
8、遍历调用所有SpringApplicationRunListener的contextPrepared()方法。
9、最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的loC容器配置加载到已经准备完毕的ApplicationContext
10、遍历调用所有SpringApplicationRunListener的contextLoaded()方法。
11、调用ApplicationContext的refresh()方法,完成loC容器可用的最后一道工序。
12、查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。
13、正常情况下,遍历执行SpringApplicationRunListener的finished()方法、(如果整个过程出现异常,则依然调用所有SpringApplicationRunListener的finished(方法,只不过这种情况下会将异常信息一并传入处理)去除事件通知点后,整个流程如下:

SpringBoot的配置加载顺序如下

SpringBoot伽载配置的优先级如下:
1.命令行参数:通过命令行参数传入的配置会覆盖其他配置。
2.Java系统属性:可以通过System.getProperties()方法获取系统属性,也可以通过命令行参数-Dkey=value来设置系统属性。
3.操作系统环境变量:可以通过System.getenv()方法获取环境变量。
4.配置文件:SpringBoot默认会读取application.properties或application.yml文件中的配置,可以通过spring.config.name和spring.config.location属性来指定其他的配置文件。
5.配置类:可以通过@Configuration注解定义一个配置类,使用@Bean注解来定义一个Bean。
6.默认配置:SpringBoot内置了一些默认配置,可以通过在application.properties或application.yml中定义相同的属性来覆盖默认配置。
在配置文件中,优先级高的配置会覆盖优先级低的配置。

BeanFactory和FactoryBean区别

BeanFactory是Spring提供的存放Bean的工厂,FactoryBean是一个可生产Bean的工厂Bean

SpringBoot项目的部署方式

  • jar包部署
  • war包部署
  • 持续集成Jenins容器部署

注解

Spring的常见注解有哪些?

嗯,这个就很多了
第一类是:声明bean,有@Component、@Service、@Repository、@Controller
第二类是:依赖注入相关的,有@Autowired、@Qualifier、@Resourse
第三类是:设置作用域 @Scope
第四类是:spring配置相关的,比如@Configuration,@ComponentScan 和 @Bean
第五类是:跟aop相关做增强的注解 @Aspect,@Before,@After,@Around,@Pointcut
Snipaste_2023-10-13_11-15-20.png

SpringMVC常见的注解有哪些?

嗯,这个也很多的
有@RequestMapping:用于映射请求路径;
@RequestBody:注解实现接收http请求的json数据,将json转换为java对象;
@RequestParam:指定请求参数的名称;
@PathViriable:从请求路径下中获取请求参数(/user/{id}),传递给方法的形式参数;@ResponseBody:注解实现将controller方法返回对象转化为json对象响应给客户端。@RequestHeader:获取指定的请求头数据,还有像@PostMapping、@GetMapping这些。
Snipaste_2023-10-13_11-18-15.png

Springboot常见注解有哪些?

嗯~~
Spring Boot的核心注解是@SpringBootApplication , 他由几个注解组成 :

  • @SpringBootConfiguration: 组合了- @Configuration注解,实现配置文件的功能;
  • @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项
  • @ComponentScan:Spring组件扫描

微信截图_20231013111901.png

Autowired和Resource注解有什么区别?

@Autowired和@Resource注解都是用于依赖注入的注解,但它们在使用方式和注入规则上有一些区别。
1. 使用方式:
- @Autowired注解是Spring提供的注解,通过类型自动装配Bean。可以用在字段、构造函数、Setter方法上,也可以用在方法参数上
- @Resource注解是Java标准的注解,通过名称或类型自动装配Bean。可以用在字段、构造函数、Setter方法上
2. 注入规则:
- @Autowired注解默认按照类型进行注入,如果有多个匹配的Bean,会根据Bean名称进行匹配。可以通过@Qualifier注解指定具体的Bean名称
- @Resource注解默认按照名称进行注入,通过name属性指定Bean的名称。如果没有指定name属性,则按照类型进行注入
3. 兼容性:
- @Autowired注解是Spring的特有注解,只能在Spring环境中使用
- @Resource注解是Java标准的注解,可以在任何Java环境中使用,但它的兼容性可能不如@Autowired
image.png
image.png

MyBatis

MyBatis执行流程

好,这个知道的,不过步骤也很多
①读取MyBatis配置文件:mybatis-config.xml加载运行环境和映射文件
②构造会话工厂SqlSessionFactory,一个项目只需要一个,单例的,一般由spring进行管理
③会话工厂创建SqlSession对象,这里面就含了执行SQL语句的所有方法
④操作数据库的接口,Executor执行器,同时负责查询缓存的维护
⑤Executor接口的执行方法中有一个MappedStatement类型的参数,封装了映射信息
⑥输入参数映射
⑦输出结果映射
Snipaste_2023-10-13_11-28-25.png

MyBAtis是否支持延迟加载?

是支持的~
延迟加载的意思是:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据
Mybatis支持一对一关联对象和一对多关联集合对象的延迟加载
在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false,默认是关闭的

延迟加载的底层原理知道吗?

嗯,我想想啊
延迟加载在底层主要使用的CGLIB动态代理完成的
第一是,使用CGLIB创建目标对象的代理对象,这里的目标对象就是开启了延迟加载的mapper
第二个是当调用目标方法时,进入拦截器invoke方法,发现目标方法是null值,再执行sql查询
第三个是获取数据以后,调用set方法设置属性值,再继续查询目标方法,就有值了
Snipaste_2023-10-13_11-39-15.png

MyBatis的一级,二级缓存用过吗?

嗯~~,用过的~
mybatis的一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当Session进行flush或close之后,该Session中的所有Cache就将清空,默认打开一级缓存
关于二级缓存需要单独开启
二级缓存是基于namespace和mapper的作用域起作用的,不是依赖于SQL session,默认也是采用 PerpetualCache,HashMap 存储
如果想要开启二级缓存需要在全局配置文件和映射文件中开启配置才行
Snipaste_2023-10-13_11-43-03.png

Mybatis的二级缓存什么时候会清理缓存中的数据

嗯!!
当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了新增、修改、删除操作后,默认该作用域下所有 select 中的缓存将被 clear

注意事项:

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

image.png

:::info
Mybatis的二级缓存是一种缓存机制,它可以将查询结果缓存到内存中,以提高查询效率。二级缓存是在Mapper级别上实现的,所有的Mapper都可以使用同一个二级缓存。

二级缓存的使用需要在Mybatis的配置文件中进行配置,可以通过以下方式开启:
<br /><settings><br /> <setting name="cacheEnabled" value="true"/><br /></settings><br />
开启二级缓存后,Mybatis会自动将查询结果缓存到内存中,下次查询相同的数据时,Mybatis会先从缓存中获取数据,如果缓存中有数据,则直接返回缓存中的数据,否则会执行SQL查询数据库并将查询结果缓存到内存中。
需要注意的是,二级缓存只缓存查询结果,不缓存更新操作。当执行更新操作时,Mybatis会自动清空相应的缓存,以保证缓存中的数据与数据库中的数据一致。
另外,二级缓存是基于Mapper级别的,因此如果两个Mapper查询相同的数据,它们会使用不同的缓存,即使它们使用相同的SQL语句。如果需要在多个Mapper之间共享缓存,可以使用Mybatis提供的命名空间(namespace)来实现。
:::

#{}和${}的区别是什么

#{}是预编译处理,KaTeX parse error: Expected 'EOF', got '#' at position 26: …br />Mybatis在处理#̲{}时,会将sql中的#{}替…{}时,就是把KaTeX parse error: Expected 'EOF', got '#' at position 19: …换成变量的值。<br />使用#̲{}可以有效的防止SQL注入,…{}
表名作参数时,必须用${}。如:select*from ${tableName}
order by时,必须用 ${}。如: select * from t_user order by ${columnName}

实体类中的属性名和表中的字段名不一样,怎么办

写sql语句时起别名,别名和属性相对应
在MyBatis的全局配置文件中开启驼峰命名规则,mybatis会将数据库中下划线的字段自动转为驼峰格式的
属性
在Mapper映射文件中使用resultMap来自定义映射规则

常见的mybatis的动态标签有哪些










在Mapper中如何传递多个参数

  • 通过实体类传参
  • 通过map传参
  • 通过定义多个@Param注解传参

Mybatis中Excutor有哪些类型

SimpleExecutor简单执行器
ResultExecutor可复用的执行器
BatchExecutor批量执行器

Mybatis如何执行批量插入

通过Mybatis的动态标签
利用Mybatis批处理特性,批量提交(ExecutorType.BATCH)

mybatis是否支持关联查询

支持
通过association, collection设置关联

Mybatis和Hibernate的区别

  1. Mybatis和hibernate不同,它不完全是一个oRM框架,因为MyBatis需要程序员自己编写Sql语句
  2. Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大
  3. Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率

是否使用过MybatisPlus自动填充功能?

原生的mybatis开发,比如数据加入时间字段,对时间字段进行维护,那么大多数修改和删除场景都会新维护一个时间值进行set,mp对此进行了统一的封装,底层加入了一个类似于拦截器的机制,在实体类属性加入tableField注解,fill属性可以设置枚举insertlinsert_update,然后实现一个mateObjecthandler接口,在进行此数据维护添加或者更新时,厨房此拦截器,那么在拦截器参数中的metObject中就封装了我们维护数据的实体类,那么我那就可以在此方法中对此类进行修改添加的时候统一进行数据填充。也可以进行类型判断执行不同的实现逻辑

Mybatis如何实现id回填

<insert id = "insertUser" useGeneratedKeys = "true' keyProperty = "id">
insert into user(username,password,access) values (#{username},{#password},#{access})
<insert>
//userGeneratedKeys="true"  是否使用了主键自增

MybatisPlus会自动主键回填

Mybatis中的mapper接口和mapper.xml中的sql如何管理?是否了解其中原理?

本质上使用的是动态代理的机制,即底层使用的是反射技术,通过mybatis生成具有访问数据库能力的具体实现类来实现:当获取到mapper接口类型的实例时,实际上获取到的是mybatis生成的代理类对象;当调用mapper接口的方法时,代理类会拦截这个方法的调用,并根据方法名找到xxxMapper.xml里的sql语句,再接着执行数据库并将结果返回给调用方

  • 25
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值