SSM框架面试题整理

Posted haijun6662022

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SSM框架面试题整理相关的知识,希望对你有一定的参考价值。

题目目录

Spring相关

1、对Spring的了解

什么是Spring?
Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯

对Spring的理解
1、Spring是一个开源框架,主要是为简化企业级应用开发而生。可以实现EJB可以实现的功能,Spring是一个IOC和AOP容器框架。

  • 控制反转(IOC):Spring容器使用了工厂模式为我们创建了所需要的对
    象,我们使用时不需要自己去创建,直接调用Spring为我们提供的对象即可,这就是控制反转的思想。
  • 依赖注入(DI):Spring使用Java Bean对象的Set方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程就是依赖注入的基本思想。
  • 面向切面编程(AOP):在面向对象编程(OOP)思想中,我们将事物纵向抽象成一个个的对象。而在面向切面编程中,我们将一个个对象某些类似的方面横向抽象成一个切面,对这个切面进行一些如权限验证,事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。

2、在Spring中,所有管理的都是JavaBean对象,而BeanFactory和ApplicationContext就是Spring框架的那个IOC容器,现在一般使用ApplicationContext,其不但包括了BeanFactory的作用,同时还进行了更多的扩展。

使用Spring框架的好处

1、轻量:Spring 是轻量的,基本的版本大约2MB。

2、控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。

3、面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。

4、容器:Spring 包含并管理应用中对象的生命周期和配置。

5、MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。

6、事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。

7、异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。

Spring的模块


核心模块

核心模块说明
Spring Core核心容器 :提供了Spring框架的基本功能。Spring以Bean的方式组织和管理Java应用中各个组件及其关系,使用BeanFactory生产和管理对象。
SpringContext应用上下文:一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能
SpringAop面向切面编程: 是面向对象编程的有效补充和完善,Spring的AOP是基于动态代理实现的,实现的方式有两种分别是Schema和AspectJ这两种方式
SpringDaoJDBC和Dao模块: JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接
SpringORM对象实体映射: Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。
SpringWebWeb模块: Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作
SpringWebMvcMVC模块:MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型由JavaBean构成,存放于m当中,而视图是一个接口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用

2、Spring使用了哪些设计模式

1、单例模式
2、原型模式
3、工厂模式
4、适配器模式
5、包装模式
6、代理模式
7、观察者模式
8、策略模式
9、模板模式

3、什么是Spring-MVC框架

Spring 配备构建Web 应用的全功能MVC框架。Spring可以很便捷地和其他MVC框架集成,如Struts,Spring 的MVC框架用控制反转把业务对象和控制逻辑清晰地隔离。它也允许以声明的方式把请求参数和业务对象绑定。

Spring-MVC常用注解

@Controller注解

是在Spring的org.springframework.stereotype包下,org.springframework.stereotype.Controller注解类型用于指示Spring类的实例是一个控制器

使用@Controller注解的类不需要继承特定的父类或者实现特定的接口,相对之前的版本实现Controller接口变的更加简单。

而Controller接口的实现类只能处理一个单一的请求动作,而@Controller注解注解的控制器可以同时支持处理多个请求动作,使程序开发变的更加灵活。 @Controller用户标记一个类,使用它标记的类就是一个Spring MVC Controller对象,即:一个控制器类。Spring使用扫描机制查找应用程序中所有基于注解的控制器类,分发处理器会扫描使用了该注解的方法,并检测该方法是否使用了@RequestMapping注解,而使用@RequestMapping注解的方法才是真正处理请求的处理器。为了保证Spring能找到控制器,我们需要完成两件事.
@RequestParam注解

下面来说org.springframework.web.bind.annotation包下的第三个注解,即:@RequestParam注解,该注解类型用于将指定的请求参数赋值给方法中的形参。那么@RequestParam注解有什么属性呢?它有4种属性,下面将逐一介绍这四种属性:

1、name属性该属性的类型是String类型,它可以指定请求头绑定的名称;
2、value属性该属性的类型是String类型,它可以设置是name属性的别名;
3、required属性该属性的类型是boolean类型,它可以设置指定参数是否必须绑定;
4、defalutValue属性该属性的类型是String类型,它可以设置如果没有传递参数可以使用默认值。

@PathVaribale注解
下面来说org.springframework.web.bind.annotation包下的第四个注解,即:@PathVaribale注解,该注解类型可以非常方便的获得请求url中的动态参数。@PathVaribale注解只支持一个属性value,类型String,表示绑定的名称,如果省略则默认绑定同名参数。

3、SpringBean

SpringBean的生命周期

1、实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。

2、设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

3、处理Aware接口:
接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:

  • 如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(StringbeanId)方法,此处传递的就是Spring配置文件中Bean的id值;
  • 如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
  • 如果这个Bean已经实现了ApplicationContextAware接口,会调用
    setApplicationContext(ApplicationContext)方法,传入Spring上下文;

4、BeanPostProcessor:
如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
5、InitializingBean 与 init-method:
如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。

6、 如果这个Bean实现了BeanPostProcessor接口,将会调用
postProcessAfterInitialization(Object obj, String s)方法;以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean

7、DisposableBean:
当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
8、destroy-method:
最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

BeanFactory和ApplicationContext有什么区别

BeanFactory是ApplicationContext接口的父接口

BeanFactory

是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。

ApplicationContext

ApplicationContext接口是由BeanFactory接口派生而来,因而具有BeanFactory所有的功能。
ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,
ApplicationContext包还提供了以下的功能:

  1. MessageSource, 提供国际化的消息访问
  2. 资源访问,如URL和文件
  3. 事件传播
  4. 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层.

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

肯定不是线程安全的,当多用户同时请求一个服务时,容器会给每一个请求分配一个线程,这是多个线程会并发执行该请求多对应的业务逻辑(成员方法),此时就要注意了,如果该处理逻辑中有对该单列状态的修改(体现为该单列的成员属性),则必须考虑线程同步问题.

Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。

Spring如何处理线程并发问题

在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。

ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

什么是Spring的内部bean

当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean,为了定义inner bean,在Spring 的 基于XML的 配置元数据中,可以在 或\\ 元素内使用 元素,内部bean通常是匿名的,它们的Scope一般是prototype。

一般写法

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="CustomerBean" class="com.dpb.common.Customer">
		<property name="person" ref="PersonBean"/>
	</bean>
	
	<bean id="PersonBean" class="com.domain.common.Person">
		<property name="name" value="阿三"/>
		<property name="address" value="陕西"/>
		<property name="age" value="18"/>
	</bean>
</beans>

改为内部bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="CustomerBean" class="com.domain.common.Customer">
		<property name="person">
			<bean class="com.domain.common.Person">
				<property name="name" value="阿三"/>
				<property name="address" value="陕西"/>
				<property name="age" value="18"/>
			</bean>
		</property>
	</bean>
</beans>

内部 bean 也支持构造器注入

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="CustomerBean" class="com.dpb.common.Customer">
		<constructor-arg >
			<bean class="com.domain.common.Person">
				<property name="name" value="阿三"/>
				<property name="address" value="陕西"/>
				<property name="age" value="18"/>
			</bean>
		</constructor-arg>
	</bean>
</beans>

id 或 name 值在bean类是没有必要以一个内部 bean 呈现

Spring Bean 有哪些作用域

singleton :这种 bean 范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个bean 的实例,单例的模式由 bean factory 自身来维护 。

prototype :原形范围与单例范围相反,为每一个 bean 请求提供一个实例 。

request :在请求 bean 范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后, bean会失效并被垃圾回收器回收 。

Session :与请求范围类似,确保每个 session 中有一个 bean 的实例,在 session 过期后, bean 会随之失效 。global-session : global-session 和 Portlet 应用相关 。 当你的应用部署在 Portlet 容器中工作时,它包含很多 portlet。 如果你想要声明让所有的 portlet 共用全局的存储变量的话,那么这全局变量需要存储在 global-session 中

4、Spring 框架有哪些自动装配模式

no :这是 Spring 框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在 bean 定义中用标签明确的设置依赖关系 。

byName :该选项可以根据 bean 名称设置依赖关系 。 当向一个 bean 中自动装配一个属性时,容器将根据 bean 的名称自动在在配置文件中查询一个匹配的 bean。 如果找到的话,就装配这个属性,如果没找到的话就报错 。

byType :该选项可以根据 bean 类型设置依赖关系 。 当向一个 bean 中自动装配一个属性时,容器将根据 bean 的类型自动在在配置文件中查询一个匹配的 bean。 如果找到的话,就装配这个属性,如果没找到的话就报错 。

constructor :构造器的自动装配和 byType 模式类似,但是仅仅适用于与有构造器相同参数的 bean,如果在容器中没有找到与构造器参数类型一致的 bean ,那么将会抛出异常 。

autodetect :该模式自动探测使用构造器自动装配或者 byType 自动装配 。 首先,首先会尝试找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在 bean 内部没有找到相应的构造器或者是无参构造器,容器就会自动选择 byTpe 的自动装配方式 。

5、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响应用户。

6、一些常用注解的区别

@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫
描机制现在可以将其拾取并将其拉入应用程序环境中。
@Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器
中。
@Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务
层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。
@Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException
@Autowired
通过类型来实现自动注入bean。和@Qualifier注解配合使用可以实现根据name注入bean。
@Qualifier
和@Autowired一块使用,在同一类型的bean有多个的情况下可以实现根据name注入的需求
@Resource
默认是根据name注入bean的,可以通过设置类型来实现通过类型来注入

@Autowire和@Resource区别

对比项@Autowire@Resource
注解来源Spring注解JDK注解
装配方式优先按照类型优先按照名称
属性requiredname,type
作用范围字段,setter方法,构造器字段,setter方法

7、SpringMVC中的拦截器和Servlet的过滤器区别

首先最核心的一点他们的拦截侧重点是不同的,SpringMVC中的拦截器是依赖JDK的反射实现的,SpringMVC的拦截器主要是进行拦截请求,通过对Handler进行处理的时候进行拦截,先声明的拦截器中的preHandle方法会先执行,然而它的postHandle方法(他是介于处理完业务之后和返回结果之前)和afterCompletion方法却会后执行。并且Spring的拦截器是按照配置的先后顺序进行拦截的。而Servlet的filter是基于函数回调实现的过滤器,Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类)

8、Spring加载流程

初始化环境—>加载配置文件—>实例化Bean—>调用Bean显示信息

9、Spring的IOC理解

1、IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。

2、最直观的表达就是,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。

3、Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
IoC让相互协作的组件保持松散的耦合,而AOP编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件。

IOC的实现原理

就是工厂模式加反射机制

Spring通知有哪些类型

1、前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
2、返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
3、抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。
4、后通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
5、环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。 环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架,例如Nanning和JBoss4,都只提供环绕通知。

10、SpringAop 实现原理

AOP(Aspect-OrientedProgramming,面向方面编程):是OOP的补充和完善。OOP引入了封装、继承、多态性等建立一种对象层次结构(从上到下的关系)。当需要为分散的对象引入公共行为的时候(从左到右的关系),OOP就显得无能为力。例如:日志功能。日志代码往往水平的散步所有对象层次中,与对象的核心功能毫无关系。这种代码被称为横切(cross-cutting)代码还有像安全性、异常处理、透明的持续性等都称为横切代码。在OOP设计中,它们导致了大量代码的重复,不利于模块的重用。
AOP与OOP相反,利用“横切”技术将影响多个类的公共行为封装到一个可重用模块,称为Aspect。简单点,就是将那些与业务无关,却被业务模块所共同调用的逻辑封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。” Spring提供了两种方式生成代理对象:JDKProxy和Cglib具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标
类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。

Spring AOP里面的几个名词

1、切面(Aspect):被抽取的公共模块,可能会横切多个对象。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。

2、连接点(Join point):指方法,在Spring AOP中,一个连接点 总是 代表一个方法的执行。

3、通知(Advice):在切面的某个特定的连接点(Join point)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。

4、切入点(Pointcut):切入点是指 我们要对哪些Join point进行拦截的定义。通过切入点表达式,指定拦截的方法,比如指定拦截add、search。

5、引入(Introduction):(也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。

6、目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(adviced) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。

7、织入(Weaving):指把增强应用到目标对象来创建新的代理对象的过程。Spring是在运行时完成织入。

切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键,这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如,一个提供声明式事务管理的around通知可以被应用到一组横跨多个对象中的方法上(例如服务层的所有业务操作)。

11、Spring事务的实现方式和实现原理

Spring事务的种类

  • 编程式事务管理使用TransactionTemplate。
  • 声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
    声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

Spring中的隔离级别

  • ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。

  • ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。

  • ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。

  • ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。

  • ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新

Spring事务的传播属性

1、PROPAGATION_REQUIRED,那么由于执行ServiceA.methodA的时候,ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没有在事务中,他就会为自己分配一个事务。这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都
会被回滚。即使ServiceB.methodB的事务已经被提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚。

2、PROPAGATION_SUPPORTS —— 支持当前事务,如果当前没有事务,就以非事务方式执行。

3、PROPAGATION_MANDATORY ——支持当前事务,如果当前没有事务,就抛出异常。

4、PROPAGATION_REQUIRES_NEW ——支持当前事务,如果当前没有事务,就将当前事务挂起。如ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,A
才继续执行。他与PROPAGATION_REQUIRED的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在两个不同的事务。如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。如果ServiceB.methodB失败回滚,如果他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。

5、PROPAGATION_NOT_SUPPORTED —— 以非事务方式执行当前操作,如果当前存在事务,就把事务挂起来。 /

6、PROPAGATION_NEVER —— 以非事务方式执行,如果当前存在事务,则抛异常。

7、PROPAGATION_NESTED—— 如果当前存在事务,则在嵌套事务内执行,关键是savepoint。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。与PROPAGATION_REQUIRES_NEW的区别是NESTED的事务和他的父事务是相依的,它的提交是要等父事务一块提交。也就是说,如果父事务最后回滚,它也要回滚。

MyBatis相关

1、对MyBatis的理解

1、Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。

2、MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

3、通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。(从执行sql到返回result的过程)。

MyBatis的优缺点

优点

1、基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。

2、与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;

3、很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。

4、能够与Spring很好的集成;

5、提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

缺点

1、SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。

2、SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库

ORM是什么

ORM(Object Relational Mapping),对象关系映射,是一种为了解决关系型数据库数据与简单Java对象(POJO)的映射关系的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系型数据库中。

JDBC编程不足之处,MyBatis如何解决

1、数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。

  • 解决:在mybatis-config.xml中配置数据链接池,使用连接池管理数据库连接。

2、Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。

  • 解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

3、向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。

  • 解决: Mybatis自动将java对象映射至sql语句。

4、对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。

  • 解决:Mybatis自动将sql执行结果映射至java对象。

2、MyBatis编程步骤

1、 创建SqlSessionFactory
2、 通过SqlSessionFactory创建SqlSession
3、 通过sqlsession执行数据库操作
4、 调用session.commit()提交事务
5、 调用session.close()关闭会话

JDBC 编程步骤

1、加载数据库驱动
2、创建数据库链接
3、创建预处理对象
4、执行Sql语句
5、返回结果集处理
6、关闭资源

3、MyBatis的工作原理

1、读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连接信息。

2、加载映射文件。映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。

3、构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。

4、创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。

5、Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。

6、MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。

7、输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参
数的过程。

8、输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。

功能架构

  • API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。
  • 数据处理层:负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。
  • 基础支撑层:负责最基础的功能支撑,包括连接管理、事务管理、配置加载和缓存处理,这些都是共用的东西,将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。

4、DBMS

数据库管理系统(database management system)是一种操纵和管理数据库的大型软件,用于建立、使用和维护数zd据库,简称dbms。它对数据库进行统一的管理和控制,以保证数据库的安全性和完整性。用户通过dbms访问数据库中的数据,数据库管理员也通过dbms进行数据库的维护工作。它可使多个应用程序和用户用不同的方法在同时版或不同时刻去建立,修改和询问数据库。DBMS提供数据定义语言DDL(Data Definition Language)与数据操作语言DML(Data Manipulation Language),供用
户定义数据库的模式结构与权限约束,实现对数据的追加权、删除等操作。

为什么需要预编译

定义:
SQL 预编译指的是数据库驱动在发送 SQL 语句和参数给 DBMS 之前对 SQL 语句进行编译,这样DBMS 执行 SQL 时,就不需要重新编译。
为什么需要预编译
JDBC 中使用对象 PreparedStatement 来抽象预编译语句,使用预编译。预编译阶段可以优化SQL 的执行。预编译之后的 SQL 多数情况下可以直接执行,DBMS 不需要再次编译,越复杂的SQL,编译的复杂度将越大,预编译阶段可以合并多次操作为一个操作。同时预编译语句对象可以重复利用。把一个 SQL 预编译后产生的 PreparedStatement 对象缓存下来,下次对于同一个SQL,可以直接使用这个缓存的 PreparedState 对象。Mybatis默认情况下,将对所有的 SQL 进行预编译。
还有一个重要的原因,防止SQL注入

5、#和$的区别是什么

  • # 是预编译处理
  • $ 是字符串替换。
    Mybatis在处理#时,会将sql中的#替换为?号,调用PreparedStatement的set方法来赋值;Mybatis在处理 时,就是把 时,就是把 时,就是把替换成变量的值。使用#可以有效的防止SQL注入,提高系统安全性。

6、缓存

1)一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。

2)二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ;

3)对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D操作后,默认该作用域下所有 select 中的缓存将被 clear。

7、接口绑定有几种实现方式

接口绑定有两种实现方式

  • 一种是通过注解绑定,就是在接口的方法上面加上@Select@Update 等注解里面包含 Sql 语句来绑定
  • 另外一种就是通过 xml 里面写 SQL 来绑定,在这种情况下,要指定 xml 映射文件里面的 namespace 必须为接口的全路径名.
    什么情况下用注解绑定,什么情况下用 xml 绑定?
    当 Sql 语句比较简单时候,用注解绑定;当 SQL 语句比较复杂时候,用 xml 绑定,一般用
    xml 绑定的比较多

8、 Mybatis 动态 sql

1、Mybatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能。

2、Mybatis 提供了 9 种动态 sql 标签:
trim、where、set、foreach、if、choose、when、otherwise、bind。

3、其执行原理为,使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql,以此来完成动态 sql 的功能。

Java面试题-SSM框架

SSM常见面试题

文章目录

三个框架:Mybatis、Spring、Spring MVC

Mybatis

https://mybatis.org/mybatis-3/zh/index.html

(1)什么是Mybatis?

1)Mybatis是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL语句本身,不需要花费精力去处理加载驱动.创建连接,创建 preparedstatement等繁杂的过程。程序员直接编写原生态 sql,可以严格控制 sql执行性能,灵活度高。

2)MyBatis可以使用 XML或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC代码和手动设置参数以及获取结果集。

3)通过 xml文件或注解的方式将要执行的各种 statement配置起来,并通过 java对象和 statement中 sql的动态参数进行映射生成最终执行的 sql语句,最后由 mybatis框架执行 sql并将结果映射为 java对象并返回。(从执行 sql到返回 result的过程)。

(2)Mybatis的优缺点?

优点:

1)基于 SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在 XML里,解除 sql与程序代码的耦合,便于统一管理;提供 XML标签,支持编写动态 SQL语句,并可重用。

2)与 JDBC相比,减少了 50%以上的代码量,消除了 JDBC大量冗余的代码,不需要手动开关连接;

3)很好的与各种数据库兼容(因为 MyBatis使用 JDBC来连接数据库,所以只要 JDBC支持的数据库,MyBatis都支持)。

4)能够与 Spring很好的集成;

5)提供映射标签,支持对象与数据库的 ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

缺点:

1)SQL语句的编写工作量大,如果涉及到字段多,或者需要进行多表联合查询,那么需要写很多的sql语句;

2)SQL语句依赖于数据库,导致数据库移植性差,无法更换数据库。

(3)Mybatis的工作原理以及实现代码?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6namyeUI-1672325209454)(F:\\姚飞鑫\\image-20210831112631631.png)]

1、加载mybatis全局配置文件(数据源、mapper映射文件等),解析配置文件,MyBatis基于XML配置文件生成Configuration,和一个MappedStatement(包括了参数映射配置、动态SQL语句、结果映射配置),其对应着<select | update | delete | insert>标签项。

2、SqlSessionFactoryBuilder通过Configuration对象生成SqlSessionFactory,用来开启SqlSession。

3、SqlSession对象完成和数据库的交互:

(1)用户程序调用mybatis接口层api(即Mapper接口中的方法)

(2)SqlSession通过调用api的Statement ID找到对应的MappedStatement对象

(3)通过Executor(负责动态SQL的生成和查询缓存的维护)将MappedStatement对象进行解析,sql参数转化、动态sql拼接,生成jdbc Statement对象

(4)JDBC执行sql。

(5)借助MappedStatement中的结果映射关系,将返回结果转化成HashMap、JavaBean等存储结构并返回。

实现代码:

public void test03() throws IOException 
    String resource = "mybatis.xml";
    //以输入流的方式加载配置文件
    InputStream inputStream = Resources.getResourceAsStream(resource);
    //通过配置文件中参数构建mybatis环境 --》 SqlSessionFactory
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //SqlSession 操作数据库
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    sqlSession.update("PersonMapper.updatePerson",new Person(4,"yao",new Date(),"guangzhou"));
    //如果是使用上面的语句的话,那么则需要去记住Mapper里面需要的语句的id,这样子需要记忆性。那么则有另一种方案可以不需要进行记忆
    
     	 PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
         Person person=personMapper.findPersonByIdOrName(6,"刘");
    //结论:使用接口代理开发好处是,最终打包时可以把配置文件和接口放在一起,并且开发时不需要记忆方法名,直接通过接口对象调用即可。大大降低程序员开发的难度。在使用的时候,需要在mybatis的配置文件中,配置扫描mapper接口类的包
     <mappers>
        <package name="com.yfx.day01.mapper"></package>
   	 </mappers>
    
    sqlSession.commit();
    sqlSession.close();

上面在进行mybatis的准备操作时,每一个测试方法都需要进行写相同的代码,那么这样会增加代码的冗余性。可以把每次进行准备操作的代码抽取出来,作为一个工具类,在测试类中使用继承方式,就可以使每一个测试的方法不用写很多的相同的代码了。

public class BaseUtils 
    private static SqlSessionFactory sqlSessionFactory;
    public SqlSession sqlSession =null;
    static

        try 
            String resource = "mybatis.xml";
            //以输入流的方式加载配置文件
            InputStream inputStream = null;
            inputStream = Resources.getResourceAsStream(resource);
            //通过配置文件中参数构建mybatis环境 --》 SqlSessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
         catch (IOException e) 
            e.printStackTrace();
        

    
    public  static SqlSession sqlSession()
        return sqlSessionFactory.openSession();
    
    //这是sqlSession执行之前
    @Before
    public void  before()
        sqlSession = BaseUtils.sqlSession();
    

    //这是sqlSession执行之后
    @After
    public void after()
        sqlSession.commit();
        sqlSession.close();
    


/*
*	这样子在测试类,就大大减少了准备操作的代码了
*  比如下面
**/
public class Persontest extends BaseUtils 

    @Test
    public void Test01()
        PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);  //需要加载mapper
        Person person = personMapper.selectByPrimaryKey(4);
        System.out.println(person);
    


(4)#和$的区别是什么?
#是预编译处理,$是字符串替换,EL表达式。
Mybatis 在处理#时,会将 sql 中的#替换为?号,调用 PreparedStatement 的set 方法来赋值;
Mybatis 在处理$时,就是把$替换成变量的值。
使用#可以有效的防止 SQL 注入,提高系统安全性 
(5)Mybatis的动态sql有哪些?

Mybatis动态 SQL可以在 Xml映射文件内,以标签的形式编写动态 sql,执行原理是根据表达式的值 完成逻辑判断并动态拼接 sql的功能。

<!--  where  if  的用法-->
<select id="findPersonByCondition" resultType="person">
    select * from person 
 <!--在sql中写查询判断  使用where 标签,可以省略多余的and,并且当一个条件都不存在时, 去除where关键字 if做条件判断语句 -->
    <where>
       <if test="id>0">
           and id=#id
       </if>
       <if test="name!=null and name != ''">
           and name=#name
       </if>
   </where>
</select>


<!-- where choose when otherwise -->
 <select id="findPersonByCondition" resultType="person">
        select * from person
        <where>
            <choose>
                <when test="id>0">
                    and id= #id
                </when>
                <when test="name!=null and name != ''">
                    and name = #name
                </when>
                <otherwise>
                    and 1=1
                </otherwise>
            </choose
        </where>
    </select>
<!--
总结:
1)使用if的标签的,可以同时满足多个条件;
2)使用when ,只能满足一种条件,如果满足的话,会去除and,如果都不满足的话,会使用otherwise;
3)choose 类似 switch选择结构,otherwise 类似 switch中的 default,类似 if中的else

-->
            
<!--set 
标签<set> 相当于 关键字set.
set 除了作为关键字,还可以去除多余的,  -->
 <update id="UpdatePersonByCondition">
        update person
        <set>
            <if test="name!=null and name != ''">
                 name=#name,
            </if>
            <if test="birthday!=null">
                 birthday=#birthday,
            </if>
        </set>
        where id = #id
    </update>

<!--trim-->
<!--
if   判断,可以同时满足多个条件
choose 选择结构
when  判断,只能满足其中一个。可以写otherwise ,相当于else,switch 里面的 default
set    替换set关键字,去掉最后一个 ,
where  替换where关键字,去掉第一个and 或者 or

trim标签的用法相对比 set、where更加全能,既可以实现动态查询,也可以实现动态修改、添加。
-->    
            
<!-- trim   prefix  前缀  suffix  后缀  prefixOverrides  过滤第一个指定的关键字  suffixOverride  过滤最后一个指定的关键字 -->            
   <update id="UpdatePersonByCondition">
        update person
        <trim prefix="set" suffix="where id=#id" suffixOverrides=",">
            <if test="name!=null and name != ''">
                name=#name,
            </if>
            <if test="birthday!=null">
                birthday=#birthday,
            </if>
            <if test="addr!=null and addr != ''">
                addr=#addr,
            </if>
        </trim>
    </update>  
            
<!--foreach  可以用来批量查询或者批量删除-->
<!--
foreach 遍历集合的标签
collection  指定传入参数的类型  collection list array
open 循环开始前的字符
close  循环结束后的字符
item   集合,数组中循环的元素,必须要和下面的#里面的一样
separator  循环中元素之间的连接符
index  下标(不常用)
-->            
           
    <select id="findPersonByIds" resultType="person">
        select * from person
        <foreach collection="list" open="where id in(" close=")" item="i" separator=",">
            #i
        </foreach>
    </select>

    <delete id="DeletPersonByIds">
        delete from person
        <foreach collection="list" open="where id in(" close=")" item="i" separator=",">
            #i
        </foreach>
    </delete>            
(6)Mybatis的XML映射文件的标签有哪些,分别用于哪些操作?
<select><update><insert><delete><resultType><resultMap><ossociation><collection><selectKey><sql><include>

前面四个就是crud语句了。resultType 采用的是自动映射,也就是映射和列名相同的结果到属性中;

当列名和属性名不一致,自动映射失败,需要使用手动映射(自定义映射),这时候就需要使用了resultMap

resultMap id 表示给当前resultMap 取一个名字,唯一标志 type 表示需要给哪个javabean 自定义映射规则 autoMapping 表示其他一样的名字的话,采用自动映射

那它里面的字标签有 column :表中的字段名 列名 ; property :对象的属性名; 在里面写具体哪一个是列名和属性名不一致的。

使用resultMap的标签有两种:第一种是上面这种情况;第二种是使用多表查询:一对一()、一对多()。下面的第七点会说到。

主键生成策略:

适用场景:在实际工作中,经常会有以下情况,需要马上显示、获取刚刚插入的数据的主键。比如添加订单、订单项

<insert id="InsertPersonJavaBean" >
    <!--
           order  设置 selectKey 中语句什么时候执行  before after
           ketcolumn   把记录中哪个字段值拿过来
           keyproperty   拿回来的字段值映射给哪个属性
           resultType 字段值的类型 
    -->
    <selectKey order="AFTER" keyColumn="id" keyProperty="id" resultType="int">
        select LAST_INSERT_ID()
    </selectKey>
    insert into  person(name,birthday,addr) <include refid="insertsql"></include> ;
</insert>

sql片段: 使用来包含导入。

适用场景:使用sql片段可以把某几段sql中 重复的代码抽取出来,当需要使用时,使用标签 引用即可,可以提高代码的可重用性,更加方便维护

可以将xml映射文件中,出现多条语句中,共同的sql部分。为了不让整个配置文件中本来出现相同的sql片段出现多次,可以使用sql标签,把共同部分抽取出来,放在标签里面,同时给sql标签赋予一个id。使用标签 中的属性refid=“ id ”可以将对应id的sql片段导进去。

补充一个重要的注解:在mybatis调用方法时,有可能传入的参数不只一个,可能有多个。这时候我们可以采用注解的方式 @Param(“ ”)

使用**@Param** 可以给指定参数赋值一个参数名,这个参数名是可以在xml中通过#获取。

@Param: 1.多个参数会使用
		2.模糊查询如果使用 $,默认是以value作为参数名,也就是必须使用 $value ,也需要使用@Param
		3.使用动态sql,并且传入的参数是基本类型,也会使用@Param

(7)Mybatis的一对一、一对多关联查询和嵌套查询?

只要发生连表查询,resultType 就不能处理得了结果映射的问题。需要使用resultMap 处理多张表之间字段和属性之间自定义映射。

处理一对一的关联映射:使用

property 表示关联映射哪个属性 javaType 表示关联属性对应的类型(所在的实体类) autoMapping 其余自动映射。

处理一对多的关联映射:使用

property 表示关联映射哪个属性 ofType 指的是集合中泛型的类型(所在的实体类) autoMapping 其余自动映射。

嵌套查询是延迟加载的前提。之前的关联查询,是在一次查询中查询多个表。

嵌套查询就是把多个表拆成一个一个表,每次执行单表,执行多次查询。

因此嵌套查询就只是在关联查询的基础上,在和中,加入select 属性:表示需要嵌套的另一个查询语句,通过namespace.id 确定下来 和 column 属性 表示 另一个嵌套查询语句的条件。

(8)Mybatis是否支持延迟加载?

延迟加载在 mybatis 中有两种实现方式: 局部延迟加载、全局延迟加载。

延迟加载必须要建立在使用 嵌套查询(因此仅支持一对一和一对多,多对多)的情况下才可以使用

Mybatis仅支持 association关联对象和 collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在 Mybatis配置文件中,可以配置是否启用延迟加载 lazyLoadingEnabled=true|false。

实现局部延迟加载策略非常简单,只需要在collection、association标签中 加上属性 <fetchType = “lazy”>。 默认是eager(立即加载的意思)

实现全局加载,在mybatis.xml中配置开启全局延迟加载。

<!--这是全局加载的,默认是false-->
<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>

需要注意的是,如果全局延迟加载开启,局部加载策略也开启,会优先选择局部的策略方式。

延迟加载的执行原理:

它的原理是,使用 CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 a.getB().getName(),拦截器 invoke()方法发现a.getB()是 null值,那么就会单独发送事先保存好的查询关联 B对象的 sql,把 B查询上来,然后调用 a.setB(b),于是 a的对象 b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

(9)Mybatis的一级缓存、二级缓存?
文档里面的:

一级缓存简介:一级缓存是SqlSession级别的缓存,是默认开启且无法关闭的。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象多次调用同一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

一级缓存要求多次查询的语句需要使用同一个sqlSession,并且执行sql和参数需要一样。

二级缓存简介:因为一级缓存存储有效范围是SqlSession,范围比较小,在实际开发中,用处并不大。实际开发中难免会经常查询数据库,为了提高数据库查询效率。使用二级缓存是一个不错的选择。

二级缓存有效范围是Mapper级别。只要两次、多次查询的方法来自于同一个namespace,name就可以使用二级缓存。

注意:
二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession级别的。

使用二级缓存的实现步骤:

第一步:在需要实现二级缓存的JavaBean类中实现序列化接口  implements Serializable;

第二步:在需要实现二级缓存的xml映射文件中添加一个标签  <cache/>

1)一级缓存:基于 PerpetualCache的 HashMap本地缓存,其存储作用域为 Session,当 Sessionflush或 close之后,该 Session中的所有 Cache就将清空,默认打开一级缓存且不能关闭。

2)二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要手动开启二级缓存,使用二级缓存属性类需要实现 Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置。

3)对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了 C/U/D操作后,默认该作用域下所有 select中的缓存将被 clear。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oitP6v20-1672325209459)(C:\\Users\\Administrator\\AppData\\Roaming\\Typora\\typora-user-images\\image-20210816204114405.png)]

(10)关于Mybatis的分页?
	Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

	分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

(一)原生的Mybatis分页

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oulS3C90-1672325209460)(C:\\Users\\Administrator\\AppData\\Roaming\\Typora\\typora-user-images\\image-20211002195616293.png)]

所以底层使用了RowBounds这个对象的两个属性(start,limit)来进行截取分页的。

缺点:内存分页(即逻辑分页),是通过将数据全部查询出来放在内存中进行的。

(二)直接写sql语句(使用limit)

(三)使用PageHelper:第三方插件 【物理分页】

步骤:

(1)导入依赖:

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.0</version>
</dependency>

(2)在Mybatis配置文件中配置:

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

(3)使用。可以在测试类进行测试一下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Zg1HTgz-1672325209461)(C:\\Users\\Administrator\\AppData\\Roaming\\Typora\\typora-user-images\\image-20210816204005495.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O7TopWD8-1672325209462)(C:\\Users\\Administrator\\AppData\\Roaming\\Typora\\typora-user-images\\image-20210816204029040.png)]

(11)传统的JDBC

步骤:

1、加载驱动 所以直接使用反射的机制 class.forName 会自动去加载里面的静态代码块 注册驱动

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W7p4XH5f-1672325209463)(C:\\Users\\Administrator\\AppData\\Roaming\\Typora\\typora-user-images\\image-20210817171339526.png)]

2、连接数据库 DriverManager

3、获得执行sql的对象 Statement PreparedStatement

4、如果是查询的话,需要获得返回的结果集 ResultSet

5、释放连接

使用不安全的执行sql对象: Statement

public class JdbcTest 
    public static void main(String[] args) 
        try 
            //1.加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            
            String url = "jdbc:mysql://localhost:3306/day01?useSSL=true&useUnicode=true&characterEncoding=utf8";
            String username = "root";
            String password = "";
            //2.连接成功  数据库对象  Connection 代表数据库  URl和用户信息
            Connection connection = DriverManager.getConnection(url, username, password);
            
            //3.执行数据库对象 Statement  
            Statement st = connection.createStatement();  // 缺点:会出现sql注入的危险   比如  select * from person where name = '' or '1=1';这样子数据库中的所有数据都泄露出来了
       		
            //执行sql的对象 去执行SQL,可能存在结果,查询返回的结果
            String sql = "select * from person where id =4";
			//4.返回的结果集 ,结果集中封装了我们全部的查询结果
            ResultSet rs = st.executeQuery(sql);  
            
            while (rs.next()) 
                System.out.println(rs.getInt("id"));
                System.out.println(rs.getString("name"));
                System.out.println(rs.getDate("birthday"));
                System.out.println("================================");
            
            
            //5.释放连接
            rs.close以上是关于SSM框架面试题整理的主要内容,如果未能解决你的问题,请参考以下文章

JAVA SSM框架基础面试题

Java-SSM框架相关面试题整理!面试真题解析

myBatis+Spring+SpringMVC框架面试题整理

SSM(Spring + Springmvc + Mybatis)框架面试题

2022最新分布式面试题合集,轻松应对Java面试

2022最新分布式面试题合集,轻松应对Java面试