SSM 面试总结

Spring 面试总结

1、什么是 Spring 框架?

Spring 是⼀种轻量级开源开发框架,旨在提⾼开发⼈员的开发效率以及系统的可维护性。

Spring 官⽹:https://spring.io/

我们⼀般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使⽤这些模块可以很⽅便地协助我们进⾏开发。这些模块是:核⼼容器、数据访问/集成,、Web、AOP(⾯向切⾯编程)、⼯具、消息和测试模块。⽐如:Core Container 中的 Core 组件是Spring 所有组件的核⼼,Beans 组件和 Context 组件是实现IOC和依赖注⼊的基础,AOP组件⽤来实现⾯向切⾯编程。

Spring 官⽹列出的 Spring 的 6 个特征:

  • 核⼼技术 :依赖注⼊(DI),AOP,事件(events),资源,i18n,验证,数据绑定,类型转换,SpEL。
  • 测试 :模拟对象,TestContext框架,Spring MVC 测试,WebTestClient。
  • 数据访问 :事务,DAO⽀持,JDBC,ORM,编组XML。
  • Web⽀持 : Spring MVC和Spring WebFlux Web框架。
  • 集成 :远程处理,JMS,JCA,JMX,电⼦邮件,任务,调度,缓存。
  • 语⾔ :Kotlin,Groovy,动态语⾔。

2、列举⼀些重要的 Spring 模块?

⽬前最新的5.x版本中 Web 模块的 Portlet 组件已经被废弃掉,同时增加了⽤于异步响应式处理的 WebFlux 组件。

在这里插入图片描述

  • Spring Core: 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IoC 依赖注⼊功能。
  • Spring Aspects : 该模块为与AspectJ的集成提供⽀持。
  • Spring AOP :提供了⾯向切⾯的编程实现。
  • Spring JDBC : Java数据库连接。
  • Spring JMS :Java消息服务。
  • Spring ORM : ⽤于⽀持Hibernate等ORM⼯具。
  • Spring Web : 为创建 Web 应⽤程序提供⽀持。
  • Spring Test : 提供了对 JUnit 和 TestNG 测试的⽀持。

3、谈谈⾃⼰对于 Spring IoC 和 AOP 的理解

IoC

IoC(Inverse of Control:控制反转)是⼀种设计思想,就是 将原本在程序中⼿动创建对象的控制权,交由 Spring 框架来管理。 IoC 在其他语⾔中也有应⽤,并⾮ Spring 特有。 IoC 容器是 Spring⽤来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。

将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注⼊。这样可以很⼤程度上简化应⽤的开发,把应⽤从复杂的依赖关系中解放出来。 IoC 容器就像是⼀个⼯⼚⼀样,当我们需要创建⼀个对象的时候,只需要配置好配置⽂件/注解即可,完全不⽤考虑对象是如何被创建出来的 [ 工厂 + 反射 ] 。在实际项⽬中⼀个 Service 类可能有⼏百甚⾄上千个类作为它的底层,假如我们需要实例化这个Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把⼈逼疯。如果利⽤ IoC 的话,你只需要配置好,然后在需要的地⽅引⽤就⾏了,这⼤⼤增加了项⽬的可维护性且降低了开发难度。

Spring 时代我们⼀般通过 XML ⽂件来配置 Bean,后来开发⼈员觉得 XML ⽂件来配置不太好,于是SpringBoot 注解配置就慢慢开始流⾏起来。

Spring IoC的初始化过程:
在这里插入图片描述


AOP

AOP (Aspect-Oriented Programming:⾯向切⾯编程) 能够将那些与业务⽆关,却为业务模块所共同调⽤的逻辑或责任(例如事务处理、⽇志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接⼝,那么Spring AOP会使⽤JDK Proxy,去创建代理对象,⽽对于没有实现接⼝的对象,就⽆法使⽤ JDK Proxy 去进⾏代理了,这时候 Spring AOP 会使⽤ Cglib ,这时候Spring AOP会使⽤ Cglib ⽣成⼀个被代理对象的⼦类来作为代理,
如下图所示:

在这里插入图片描述

当然你也可以使⽤ AspectJ ,Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java ⽣态系统中最完整的 AOP 框架了。

使⽤ AOP 之后我们可以把⼀些通⽤功能抽象出来,在需要⽤到的地⽅直接使⽤即可,这样⼤⼤简化了代码量。我们需要增加新功能时也⽅便,这样也提⾼了系统扩展性。⽇志功能、事务管理等等场景都⽤到了 AOP 。


4、Spring AOP 和 AspectJ AOP 有什么区别?

Spring AOP 属于运⾏时增强,⽽ AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),⽽ AspectJ 基于字节码操作(Bytecode Manipulation)。

Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java ⽣态系统中最完整的 AOP 框架了。AspectJ 相⽐Spring AOP 功能更加强⼤,但是 Spring AOP 相对来说更简单,

如果我们的切⾯⽐᫾少,那么两者性能差异不⼤。但是,当切⾯太多的话,最好选择 AspectJ ,它⽐ Spring AOP 快很多。


5、Spring 中的 bean 的作⽤域有哪些?

xml 配置文件中通过 scope 设置

  • singleton : 唯⼀ bean 实例,Spring 中的 bean 默认都是单例的。
  • prototype : 每次请求都会创建⼀个新的 bean 实例。
  • request : 每⼀次HTTP请求都会产⽣⼀个新的 bean,该 bean 仅在当前HTTP request 内有效。
  • session : 每⼀次HTTP请求都会产⽣⼀个新的 bean,该bean 仅在当前 HTTP session 内有效。

6、Spring 中的单例 bean 的线程安全问题了解吗?

⼤部分时候我们并没有在系统中使⽤多线程,所以很少有⼈会关注这个问题。单例 bean 存在线程问题,主要是因为当多个线程操作同⼀个对象的时候,对这个对象的⾮静态成员变量的写操作会存在线程安全问题。

常⻅的有两种解决办法:

  1. 在 Bean 对象中尽量避免定义可变的成员变量(不太现实)。
  2. 在类中定义⼀个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的⼀种⽅式)。

7、@Component 和 @Bean 的区别是什么?

  1. 作⽤对象不同: @Component 注解作⽤于类,⽽ @Bean 注解作⽤于⽅法。
  2. @Component 通常是通过类路径扫描来⾃动侦测以及⾃动装配到 Spring 容器中(我们可以使⽤ @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类⾃动装配到 Spring 的 bean 容器中)。 @Bean 注解通常是我们在标有该注解的⽅法中定义产⽣这个 bean, @Bean 告诉了Spring这是某个类的示例,当我需要⽤它的时候还给我。
  3. @Bean 注解⽐ Component 注解的⾃定义性更强,⽽且很多地⽅我们只能通过 @Bean 注解来注册 bean。⽐如当我们引⽤第三⽅库中的类需要装配到 Spring 容器时,则只能通过 @Bean 来实现。

8、将⼀个类声明为 Spring 的 bean 的注解有哪些?

我们⼀般使⽤ @Autowired 注解⾃动装配 bean,要想把类标识成可⽤于 @Autowired 注解⾃动装配的 bean 的类,采⽤以下注解可实现:

  • @Component :通⽤的注解,可标注任意类为 Spring 组件。如果⼀个Bean不知道属于哪个层,可以使⽤ @Component 注解标注。
  • @Repository : 对应持久层即 Dao 层,主要⽤于数据库相关操作。
  • @Service : 对应服务层,主要涉及⼀些复杂的逻辑,需要⽤到 Dao层。
  • @Controller : 对应 Spring MVC 控制层,主要⽤户接受⽤户请求并调⽤ Service 层返回数据给前端⻚⾯。

四种注解效果是一样的,使用不同的名字只是为了开发人员更好的进行区分


9、Spring 中的 bean ⽣命周期 ?

在这里插入图片描述


10、Spring 框架中⽤到了哪些设计模式?

  • ⼯⼚设计模式 : Spring 使⽤⼯⼚模式通过 BeanFactory 、 ApplicationContext 创建 bean 对象。
  • 代理设计模式 : Spring AOP 功能的实现。
  • 单例设计模式 : Spring 中的 Bean 默认都是单例的。
  • 包装器设计模式 : 我们的项⽬需要连接多个数据库,⽽且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
  • 观察者模式: Spring 事件驱动模型就是观察者模式很经典的⼀个应⽤。
  • 适配器模式 :Spring AOP 的增强或通知(Advice)使⽤到了适配器模式、spring MVC 中也是⽤到了适配器模式适配 Controller 。

11、Spring 管理事务的⽅式有⼏种?

  1. 编程式事务,在代码中硬编码。(不推荐使⽤)
  2. 声明式事务,在配置⽂件中配置(推荐使⽤)

声明式事务⼜分为两种:

  1. 基于XML的声明式事务
  2. 基于注解的声明式事务

12、Spring 事务中哪⼏种事务传播⾏为?

七种事务传播行为,常用 REQUIREDREQUIRES_NEW

⽀持当前事务的情况:

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加⼊该事务;如果当前没有事务,则创建⼀个新的事务。
  • TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加⼊该事务;如果当前没有事务,则以⾮事务的⽅式继续运⾏。
  • TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加⼊该事务;如果当
    前没有事务,则抛出异常。(mandatory:强制性)

不⽀持当前事务的情况:

  • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建⼀个新的事务,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以⾮事务⽅式运⾏,如果当前存在事务,则把当前事务挂起。
  • TransactionDefinition.PROPAGATION_NEVER: 以⾮事务⽅式运⾏,如果当前存在事务,则抛出异常。

其他情况:

  • TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建⼀个事务作为当前事务的嵌套事务来运⾏;如果当前没有事务,则该取值等价于 TransactionDefinition.PROPAGATION_REQUIRED。

13、如果没有事务,可能有什么问题 ?

有三个读问题:脏读、不可重复读、虚(幻)读


14、Spring 事务中的隔离级别有哪⼏种?

TransactionDefinition 接⼝中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT: 使⽤后端数据库默认的隔离级别,Mysql 默认采
    ⽤的 REPEATABLE_READ 隔离级别 Oracle 默认采⽤的 READ_COMMITTED隔离级别.
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的
    数据变更,可能会导致脏读、幻读或不可重复读
  • TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以
    阻⽌脏读,但是幻读或不可重复读仍有可能发⽣
  • TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同⼀字段的多次读取结果都是⼀致
    的,除⾮数据是被本身事务⾃⼰所修改,可以阻⽌脏读和不可重复读,但幻读仍有可能发⽣。
  • TransactionDefinition.ISOLATION_SERIALIZABLE: 最⾼的隔离级别,完全服从 ACID 的隔离级
    别。所有的事务依次逐个执⾏,这样事务之间就完全不可能产⽣⼲扰,也就是说,该级别可以防
    ⽌脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会⽤到该级别。

13、@Transactional(rollbackFor = Exception.class)注解了解吗?

我们知道:Exception分为运⾏时异常RuntimeException和⾮运⾏时异常。事务管理对于企业应⽤来说是⾄关重要的,即使出现异常情况,它也可以保证数据的⼀致性。

当 @Transactional 注解作⽤于类上时,该类的所有 public ⽅法将都具有该类型的事务属性,同时,我们也可以在⽅法级别使⽤该标注来覆盖类级别的定义。如果类或者⽅法加了这个注解,那么这个类⾥⾯的⽅法抛出异常,就会回滚,数据库⾥⾯的数据也会回滚。

在 @Transactional 注解中如果不配置 rollbackFor 属性,那么事物只会在遇到 RuntimeException 的时候才会回滚,加上 rollbackFor=Exception.class ,可以让事物在遇到⾮运⾏时异常时也回滚。


14、如何使⽤ JPA 在数据库中⾮持久化⼀个字段?

假如我们有有下⾯⼀个类:

Entity(name="USER")
public class User {
 
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column(name = "ID")
 private Long id;
 
 @Column(name="USER_NAME")
 private String userName;
 
 @Column(name="PASSWORD")
 private String password;
 
 private String secrect;
 
}

如果我们想让 secrect 这个字段不被持久化,也就是不被数据库存储怎么办?我们可以采⽤下⾯⼏种⽅法:

static String transient1; // not persistent because of static
final String transient2 = “Satish”; // not persistent because of final
transient String transient3; // not persistent because of transient
@Transient
String transient4; // not persistent because of @Transient

⼀般使⽤后⾯两种⽅式⽐᫾多,我个⼈使⽤注解的⽅式⽐较多。


Spring MVC 面试总结

1、什么是 SpringMVC ?

答:SpringMVC 是 spring 的一个模块,基于 MVC 的一个框架,无需中间整合层来整合


2、Spring MVC 的优点:

答:

1)它是基于组件技术的.全部的应用对象,无论控制器和视图,还是业务对象之类的都是 java 组件.并且和 Spring 提供的其他基础结构紧密集成.

2)不依赖于 Servlet API(目标虽是如此,但是在实现的时候确实是依赖于 Servlet 的)

3)可以任意使用各种视图技术,而不仅仅局限于 JSP

4)支持各种请求资源的映射策略

5)它应是易于扩展的


3、SpringMVC 工作原理?

答:

1)客户端发送请求到 DispatcherServlet

2)DispatcherServlet 查询 handlerMapping 找到处理请求的 Controller

3)Controller 调用业务逻辑后,返回 ModelAndView

4)DispatcherServlet 查询 ModelAndView,找到指定视图

5)视图将结果返回到客户端


4、SpringMVC 流程?

答:

  1. 客户端的所有请求都交给前端控制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的请求。
  2. DispatcherServlet收到请求后,将根据请求的信息(包括URL、HTTP协议方法、请求头、请求参数、Cookie等)以及HandlerMapping的配置找到处理该请求的Handler(任何一个对象都可以作为请求的Handler)。
  3. 在这个地方Spring会通过HandlerAdapter对该处理器进行封装。
  4. HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用 [ 调用具体的处理器 Controller ]。
  5. Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。
  6. ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作。
  7. 当得到真正的视图对象后,DispatcherServlet会利用视图对象对模型数据进行渲染。
  8. 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件。

6、SpringMVC 的控制器是不是单例模式,如果是,有什么问题,怎么解决?

答:是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,

​ 解决方案是在控制器里面不能写字段


7、如果你也用过 struts2. 简单介绍下 springMVC 和 struts2 的区别有哪些?

答:

1)springmvc 的入口是一个 servlet 即前端控制器,而 struts2 入口是一个 filter 过虑器。

2)springmvc 是基于方法开发(一个 url 对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2 是基于类开发,传递参数是通过类的属性,只能设计为多例。

3)Struts 采用值栈存储请求和响应的数据,通过 OGNL 存取数据,springmvc 通过参数解析器是将 request 请求内容解析,并给方法形参赋值,将数据和视图封装成 ModelAndView对象,最后又将 ModelAndView 中的模型数据通过 reques 域传输到页面。Jsp 视图解析器默认使用 jstl。


8、SpingMvc 中的控制器的注解一般用那个,有没有别的注解可以替代?

答:一般用 @Conntroller 注解,表示是表现层,不能用用别的注解代替。


9、 @RequestMapping 注解用在类上面有什么作用?

答:是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。


10、怎么样把某个请求映射到特定的方法上面?

答:直接在方法上面加上注解 @RequestMapping,并且在这个注解里面写上要拦截的路径


11、如果在拦截请求中,我想拦截 get 方式提交的方法,怎么配置?

答:可以在 @RequestMapping 注解里面加上 method=RequestMethod.GET


12、怎么样在方法里面得到 Request,或者 Session?

答:直接在方法的形参中声明 request,SpringMVC 就自动把 request 对象传入


13、我想在拦截的方法里面得到从前台传入的参数,怎么得到?

答:直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样


14、如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象?

答:直接在方法中声明这个对象,SpringMvc 就自动会把属性赋值到这个对象里面。


15、SpringMvc 中函数的返回值是什么?

答:返回值可以有很多类型,有 String, ModelAndView,当一般用 String 比较好。


16、SpringMVC 怎么样设定重定向和转发的?

答:在返回值前面加"forward:“就可以让结果转发,譬如"forward:user.do?name=method4” 在返回值前面加"redirect:“就可以让返回值重定向,譬如"redirect:http://www.baidu.com”


17、SpringMVC 用什么对象从后台向前台传递数据的?

答:通过 ModelMap 对象,可以在这个对象里面用 put 方法,把对象加到里面,前台就可以通过 el 表达式拿到。


18、SpringMvc 中有个类把视图和数据都合并的一起的,叫什么?

答:叫 ModelAndView。


19、怎么样把 ModelMap 里面的数据放入 Session 里面?

答:可以在类上面加上@SessionAttributes 注解,里面包含的字符串就是要放入 session 里面的 key


20、SpringMVC 怎么和 AJAX 相互调用的?

答:

通过 Jackson 框架就可以把 Java 里面的对象直接转化成 Js 可以识别的 Json 对象。

具体步骤如下 :

1)加入 Jackson.jar

2)在配置文件中配置 json 的映射

3)在接受 Ajax 方法里面可以直接返回 Object,List 等,但方法前面要加上@ResponseBody 注解


21、当一个方法向 AJAX 返回特殊对象,譬如 Object,List 等,需要做什么处理?

答:要加上@ResponseBody 注解


22、SpringMVC 里面拦截器是怎么写的

答:有两种写法,一种是实现接口,另外一种是继承适配器类,然后在 SpringMvc 的配置文件中

配置拦截器即可:

<!-- 配置 SpringMvc 的拦截器 -->
<mvc:interceptors> 
     <!-- 配置一个拦截器的 Bean 就可以了 默认是对所有请求都拦截 --> 
     <bean id="myInterceptor" class="com.et.action.MyHandlerInterceptor"></bean> 
     <!-- 只针对部分请求拦截 --> 
     <mvc:interceptor> 
         <mvc:mapping path="/modelMap.do" /> 
         <bean class="com.et.action.MyHandlerInterceptorAdapter" /> 
 	</mvc:interceptor>
</mvc:interceptors>

23、过滤器和拦截器的区别?

1.使用范围和规范不同

  • filter 是 servlet 规范规定的,只能用在 web 程序中
  • 拦截器即可以用在 web 程序中, 也可以用于 application, swing 程序中, 是 Spring 容器内的, 是 Spring 框架支持的

2.触发时机不同

顺序: Filter–>Servlet–>Interceptor–>Controller

  • 过滤器是在请求进入容器后,但请求进入 servlet 之前进行预处理的。请求结束返回也是,是在 servlet 处理完后,返回给前端之前过滤器处理。
  • 拦截器是方法到达 Controller 层之前生效的

3.过滤器的实现基于回调函数,而拦截器(代理模式)的实现基于反射

4.在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

5.拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。

6.拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。

7.拦截器可以获取IOC容器中的各个bean,而过滤器就不行,在拦截器里注入一个service,可以调用业务逻辑。

在这里插入图片描述
在这里插入图片描述


Spring 拦截器的执行顺序

Springmvc 的拦截器实现 HandlerInterceptor 接口后,会有三个抽象方法需要实现,分别为方法前执行 preHandle,方法后 postHandle,页面渲染后afterCompletion。

  1. 当俩个拦截器都实现放行操作时,顺序为preHandle 1,preHandle 2,postHandle 2,postHandle 1,afterCompletion 2,afterCompletion 1
  2. 当第一个拦截器preHandle返回false,也就是对其进行拦截时,第二个拦截器是完全不执行的,第一个拦截器只执行preHandle部分。
  3. 当第一个拦截器preHandle返回true,第二个拦截器preHandle返回false,顺序为preHandle 1,preHandle 2 ,afterCompletion 1

总结:

preHandle 按拦截器定义顺序调用
postHandler 按拦截器定义逆序调用
afterCompletion 按拦截器定义逆序调用
postHandler 在拦截器链内所有拦截器返成功调用
afterCompletion 只有preHandle返回true才调用

24.Spring MVC 怎么将数据存储到 session 中?

我一般都是使用 Servlet-Api,在处理请求的方法参数列表中,添加一个 HTTPSession 对象,之后 SpringMVC 就可以自动注入进来了。在方法体中调用 session.setAttribute 就可以了。


25.SpringMVC 的常用注解

@Component: 会被spring容器识别,并转为bean。

@Repository: 对Dao实现类进行注解。

@Service: 对业务逻辑层进行注解。

@Controller: 表明这个类是 Spring MVC 里的Controller,将其声明为Spring的一个Bean,Dispatch Servlet会自动扫描注解了此注解的类,并将Web请求映射到注解了@RequestMapping的方法上。

@RequestMapping: 用来映射Web请求(访问路径和参数)、处理类和方法的。它可以注解在类和方法上。注解在方法上的@RequestMapping路径会继承注解在类上的路径。

@ResponseBody:可以将整个返回结果以某种格式返回,如 json 或 xml 格式。

@PathVariable: 用来接收路径参数,如/news/001,可接收001作为参数,此注解放置在参数前。

@RequestParam:用于获取传入参数的值。

@RestController:是一个组合注解,组合了@Controller和@ResponseBody,意味着当只开发一个和页面交互数据的控制的时候,需要使用此注解。


MyBatis 面试总结

1、#{ } 和 ${ } 的区别是什么?

  • ${ } 是 Properties ⽂件中的变量占位符 [ 字符串替换 ],它可以⽤于标签属性值和 sql 内部,属于静态⽂本替换,

    ⽐如 ${driver} 会被静态替换为 com.mysql.jdbc.Driver 。

  • #{ } 是 sql 的参数占位符 [ 预编译处理 ],Mybatis 会将 sql 中的 #{ } 替换为 ? 号,在 sql 执⾏前会使⽤ PreparedStatement 的参数设置 [ set ]⽅法,按序给 sql 的 ? 号占位符设置参数值,

    ⽐如 ps.setInt(0,parameterValue), #{item.name} 的取值⽅式为使⽤反射从参数对象中获取 item 对象的 name 属性值,相当 param.getItem().getName()

  • 使用 #{ } 可以有效的防止 SQL 注入,提高系统安全性


2、 Xml 映射⽂件中,除了常⻅的 select | insert | update | delete 标签之外,还有哪些标签?

<resultMap>:做结果映射

<sql> 、 <include>: 用来定义可重用的 sql 代码片段,通过 标签引⼊ sql ⽚段

<selectKey>:为不⽀持⾃增的主键⽣成策略标签

加上动态 sql 的 9 个标签, if | choose | when | otherwise | trim | where | set | foreach | bind 等,


3、最佳实践中,通常⼀个 Xml 映射⽂件,都会写⼀个 Dao 接⼝与之对应,请问,这个 Dao 接⼝的⼯作原理是什么?Dao 接⼝⾥的⽅法,参数不同时,⽅法能重载吗?

答:Dao 接⼝,就是⼈们常说的 Mapper 接⼝,接⼝的全限名,就是映射⽂件中的 namespace 的值,接⼝的⽅法名,就是映射⽂件中 MappedStatement 的 id 值,接⼝⽅法内的参数,就是传递给 sql 的参数。 Mapper 接⼝是没有实现类的,当调⽤接⼝⽅法时,接⼝全限名+⽅法名拼接字符串作为 key值,可唯⼀定位⼀个 MappedStatement ,

举例: com.mybatis3.mappers.StudentDao.findStudentById ,可以唯⼀找到 namespace 为 com.mybatis3.mappers.StudentDao 下⾯ id = findStudentById 的MappedStatement 。在 Mybatis 中,每⼀个 、 、 、 标签,都会被解析为⼀个 MappedStatement 对象。

Dao 接⼝⾥的⽅法,是不能重载的,因为是全限名+⽅法名的保存和寻找策略。

Dao 接⼝的⼯作原理是 JDK 动态代理,Mybatis 运⾏时会使⽤ JDK 动态代理为 Dao 接⼝⽣成代理 proxy 对象,代理对象 proxy 会拦截接⼝⽅法,转⽽执⾏ MappedStatement 所代表的 sql,然后将 sql 执⾏结果返回。


4、Mybatis 是如何进⾏分⻚的?分⻚插件的原理是什么?

(1)Mybatis 可以使⽤ RowBounds 对象进⾏分⻚,它是针对 ResultSet 结果集执⾏的内存分⻚;

​ 也可以在 sql 内直接书写带有物理分⻚的参数来完成物理分⻚功能;

​ 也可以使⽤分⻚插件来完成物理分⻚。

(2)分页插件的原理:实现 MyBatis 提供的接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql,然后重写 sql,根据 dialect ⽅⾔,添加对应的物理分⻚语句和物理分⻚参数。

举例:select * from student,拦截 sql 后重写为:select t.* from (select * from student)t limit 0,10


5、简述 Mybatis 的插件运⾏原理,以及如何编写⼀个插件?

(1)Mybatis 仅可以编写针对 ParameterHandler 、 ResultSetHandler 、 StatementHandler 、 Executor 这 4 种接⼝的插件,Mybatis 使⽤ JDK 的动态代理,为需要拦截的接⼝⽣成代理对象以实现接⼝⽅法拦截功能,每当执⾏这 4 种接⼝对象的⽅法时,就会进⼊拦截⽅法,具体就是 InvocationHandler 的 invoke() ⽅法,当然,只会拦截那些你指定需要拦截的⽅法。

(2)实现 Mybatis 的 Interceptor 接⼝并复写 intercept() ⽅法,然后在给插件编写注解,指定要拦截哪⼀个接⼝的哪些⽅法即可,记住,别忘了在配置⽂件中配置你编写的插件。


6、Mybatis 执⾏批量插⼊,能返回数据库主键列表吗?

答:能,JDBC 都能,Mybatis 当然也能。


7、Mybatis 动态 sql 是做什么的?都有哪些动态 sql?能简述⼀下动态 sql 的执⾏原理不?

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

2)Mybatis 提供了 9 种动态 sql 标签:if | choose | when | otherwise | trim | where | set | foreach | bind 等,

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


8、 Mybatis 是如何将 sql 执⾏结果封装为⽬标对象并返回的?都有哪些映射形式?

第一种是使用标签,逐一定义列名和对象属性名之间的映射关系。

第二种是使用 sql 列的别名功能,将列别名书写为对象属性名,比如 T_NAME AS NAME,对象属性名一般是 name,小写,但是列名不区分大小写,Mybatis 会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成 T_NAME AS NaMe,Mybatis 一样可以正常工作。

有了列名与属性名的映射关系后,Mybatis 通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。


9、 Mybatis 能执⾏⼀对⼀、⼀对多的关联查询吗?都有哪些实现⽅式,以及它们之间的区别?

答:能,Mybatis 不仅可以执⾏⼀对⼀、⼀对多的关联查询,还可以执⾏多对⼀,多对多的关联查询,多对⼀查询,其实就是⼀对⼀查询,只需要把 selectOne() 修改为 selectList() 即可;多对多查询,其实就是⼀对多查询,只需要把selectOne() 修改为 selectList() 即可。

关联对象查询,有两种实现⽅式,⼀种是单独发送⼀个 sql 去查询关联对象,赋给主对象,然后返回主对象。另⼀种是使⽤嵌套查询,嵌套查询的含义为使⽤ join 查询,⼀部分列是 A 对象的属性值,另外⼀部分列是关联对象 B 的属性值,好处是只发⼀个 sql 查询,就可以把主对象和其关联对象查出来。

那么问题来了,join 查询出来 100 条记录,如何确定主对象是 5 个,⽽不是 100 个?其去重复的原理是 标签内的 ⼦标签,指定了唯⼀确定⼀条记录的 id 列,Mybatis 根据列值来完成 100 条记录的去重复功能, 可以有多个,代表了联合主键的语意。同样主对象的关联对象,也是根据这个原理去重复的,尽管⼀般情况下,只有主对象会有重复记录,关联对象⼀般不会重复。


10、 Mybatis 是否⽀持延迟加载?如果⽀持,它的实现原理是什么?

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

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


11、Mybatis 的 Xml 映射⽂件中,不同的 Xml 映射⽂件,id 是否可以重复?

答:不同的 Xml 映射⽂件,如果配置了 namespace,那么 id 可以重复;如果没有配置 namespace,那么 id 不能重复;毕竟 namespace 不是必须的,只是最佳实践⽽已。

原因就是 namespace+id 是作为 Map<String, MappedStatement> 的 key 使⽤的,如果没有namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,⾃然 id 就可以重复,namespace 不同,namespace+id ⾃然也就不同。


12、 Mybatis 中如何执⾏批处理?

答:使⽤ BatchExecutor 完成批处理。


13、 Mybatis 都有哪些 Executor 执⾏器?它们之间的区别是什么?

Mybatis 有三种基本的 Executor 执⾏器, SimpleExecutorReuseExecutorBatchExecutor

SimpleExecutor :每执⾏⼀次 update 或 select,就开启⼀个 Statement 对象,⽤完⽴刻关闭 Statement 对象。

ReuseExecutor :执⾏ update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使⽤,不存在就创建,⽤完后,不关闭 Statement 对象,⽽是放置于 Map<String, Statement>内,供下⼀次使⽤。简⾔之,就是重复使⽤ Statement 对象。

BatchExecutor :执⾏ update(没有 select,JDBC 批处理不⽀持 select),将所有 sql 都添加到批处理中(addBatch()),等待统⼀执⾏(executeBatch()),它缓存了多个 Statement 对象,每个Statement 对象都是 addBatch()完毕后,等待逐⼀执⾏ executeBatch()批处理。与 JDBC 批处理相同。

作⽤范围:Executor 的这些特点,都严格限制在 SqlSession ⽣命周期范围内。


14、 Mybatis 中如何指定使⽤哪⼀种 Executor 执⾏器?

答:

在 Mybatis 配置⽂件中,可以指定默认的 ExecutorType 执⾏器类型,

也可以⼿动给DefaultSqlSessionFactory 的创建 SqlSession 的⽅法传递 ExecutorType 类型参数。


15 、Mybatis 是否可以映射 Enum 枚举类?

答:Mybatis 可以映射枚举类,不单可以映射枚举类,Mybatis 可以映射任何对象到表的⼀列上。

映射⽅式为⾃定义⼀个 TypeHandler ,实现 TypeHandler 的 setParameter() 和 getResult() 接⼝⽅法。 TypeHandler 有两个作⽤,⼀是完成从 javaType ⾄ jdbcType 的转换,⼆是完成 jdbcType ⾄javaType 的转换,体现为 setParameter() 和 getResult() 两个⽅法,分别代表设置 sql 问号占位符参数和获取列查询结果。


16 、Mybatis 映射⽂件中,如果 A 标签通过 include 引⽤了 B 标签的内容,请问,B 标签能否定义在 A 标签的后⾯,还是说必须定义在 A 标签的前⾯?

答:虽然 Mybatis 解析 Xml 映射⽂件是按照顺序解析的,但是,被引⽤的 B 标签依然可以定义在任何地⽅,Mybatis 都可以正确识别。

原理是,Mybatis 解析 A 标签,发现 A 标签引⽤了 B 标签,但是 B 标签尚未解析到,尚不存在,此时,Mybatis 会将 A 标签标记为未解析状态,然后继续解析余下的标签,包含 B 标签,待所有标签解析完毕,Mybatis 会重新解析那些被标记为未解析的标签,此时再解析 A 标签时,B 标签已经存在,A标签也就可以正常解析完成了。


17、 简述 Mybatis 的 Xml 映射⽂件和 Mybatis 内部数据结构之间的映射关系?

答:Mybatis 将所有 Xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 Xml 映射⽂件中, 标签会被解析为 ParameterMap 对象,其每个⼦元素会被解析为 ParameterMapping 对象。 标签会被解析为 ResultMap 对象,其每个⼦元素会被解析为 ResultMapping 对象。每⼀个 、、、 标签均会被解析为 MappedStatement 对象,标签内的 sql 会被解析为 BoundSql 对象。


18、 为什么说 Mybatis 是半⾃动 ORM 映射⼯具?它与全⾃动的区别在哪⾥?

答:Hibernate 属于全⾃动 ORM 映射⼯具,使⽤ Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全⾃动的。⽽ Mybatis 在查询关联对象或关联集合对象时,需要⼿动编写 sql 来完成,所以,称之为半⾃动 ORM 映射⼯具。


19、MyBatis 与 Hibernate 有哪些不同?

  • Hibernate是全自动的,MyBatis是半自动的 Hibernate实现了部分自动生成SQL
  • MyBatis真正实现了java代码和 sql 的分离
  • SQL优化上 MyBatis强于Hibernate
  • MyBatis优化维护方便 SQL全存在于XML中 不需要修改源代码
  • 开发效率上 Hibernate略强于mybatiss
  • 从性能上说 因为Mybatis全都是自己手写的SQL,因此性能相对较高反之。Hibernate更加提倡使用HQL,HQL往往会查询更多的字段,从而性能反而较低

参考:JavaGuide面试

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值