Java八股文面试之框架篇(Spring、SpringMVC、Mybatis)

文章目录

一.Spring

Spring是什么?(或者问IOC和AOP的理解)

(1)Spring是一个开源框架,是整个生态的基石(SpringBoot、SpringCloud等都是以Spring为基石的)
(2)Spring是为了简化企业开发而生的,使得开发变得更加优雅和简介
(3)Spring是一个以IOC和AOP为核心的容器框架
①IOC:即控制反转,是一种设计思想,在java开发中,将你设计好的对象交给spring容器控制,而不是显示的用代码进行对象的创建。控制反转的思想完全颠覆了应用程序组件获取资源的传统方式:改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可,极大的降低了学习成本,提高了开发的效率。这种行为也称为查找的被动形式。
②DI,即依赖注入。DI 是 IOC 的具体实现方式:即组件以一些预先定义好的方式(例如:set 注入,构造器注入等)接收来自于容器的资源注入。总结就是:IOC 是一种控制反转的思想, 而 DI 是对 IOC 的一种具体实现。
③AOP:即⾯向切⾯编程,是⼀种编程思想。将与核⼼业务⽆关的通用交叉业务(比如日志、缓存、事务管理等)独⽴的抽取出来,形成⼀个横向的切面为独⽴的组件,交叉业务是横向的,核心业务是纵向的,以横向交叉的⽅式应⽤到业务流程当中的过程被称为AOP。AOP是对OOP(面向对象)的补充延伸。AOP底层使⽤的就是动态代理来实现的。Spring的AOP使⽤的动态代理是:JDK动态代理 + CGLIB动态代理技术。Spring在这两种动态代理中灵活切换,如果是代理接⼝,会默认使⽤JDK动态代理,如果要代理某个类,这个类没有实现接⼝,就会切换使⽤CGLIB。我们可以强制通过⼀些配置让Spring只使⽤CGLIB。
④容器:包含并管理应用对象的生命周期,就好比用桶装水一样,spring就是桶,而对象就是水

Spring有什么用?

(1)你可以轻松的写一个web应用
Spring框架有一个模块叫做SpringMVC,你可以利用该模块来开发Web应用。

Bean的依赖注入方式有哪些?

(1)set方法
(2)构造方法

Spring的注解

(1)@Component:将类标识为普通组件,@Controller:将类标识为控制层组件,@Service:将类标识为业务层组件,@Repository:将类标识为持久层组件
(2)@Configuration:放在一个类的上面,表示这个类是作为配置文件使用的
(3)@Bean:声明对象,把对象注入到容器中
(4)@Component 注解作用于类,而 @Bean 注解作用于方法;@Bean 注解比 @Component 注解的自定义性更强,有些地方我们只能通过 @Bean 注解来注册 bean。比如当我们引用第三方库中的类需要装配到 Spring 容器时,只能通过 @Bean 来实现。

Spring的优势是什么?

(1)方便解耦,简化开发
通过Spring提供的IOC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的的过度耦合。用户也不在为
单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用
(2)AOP编程的支持
通过Spring的AOP功能,方便进行切面编程,许多不容易用传统OOP实现的功能可以通过AOP轻松实现
(3)声明式事务的支持
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务管理,提高开发效率和质量
(4)可以用非容器依赖的方式

创建IOC容器的方式

(1)BeanFactory
①Spring 框架自用
②延迟加载
(2)ApplicationContext
①BeanFactory 的子接口
②面向使用 Spring 框架的开发者
③立即加载

Spring的5种不同方式的自动装配

Spring 装配包括手动装配和自动装配,手动装配有基于 xml 装配、构造方法、setter方法等。自动装配有五种自动装配的方式,可以用来指导 Spring 容器用自动装配方式来进行依赖注入。
(1)no:是默认的方式,不进行自动装配, 通过显式设置 ref 属性来进行依赖注入
(2)byName:Spring容器会根据Bean的名称自动将相应的依赖注入到需要的地方
(3)byType:Spring容器会根据Bean的类型自动将相应的依赖注入到需要的地方。如果有多 个 bean 符合条件, 则抛出错误。
(4)constructor:Spring容器会根据构造函数的参数类型自动将相应的依赖注入到构造函数中,如果没有确定的带参数的构造器参数类型, 将会抛出异常。
(5)autodetect:首先尝试使用 constructor 来自动装配,如果无法工作, 则使用byType 方式。

Bean的生命周期

在这里插入图片描述

什么是事务,Spring有事务吗?

(1)事务是指多个操作在逻辑上构成一组操作,要么都执行,要么都不执行
(2)Spring是没有事务的,Spring事务的本质是对数据库事务的包装

Spring的事务是如何回滚的?(Spring的事务管理是如何实现的)

spring的事务是由AOP来实现的,首先要生成具体的代理对象,然后按照AOP的整套流程来执行具体的操作逻辑。通过一个TransactionInterceptor来实现,并调用invoke来实现具体的逻辑:
(1)先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务
(2)如果需要开启,则获取数据库的连接,关闭自动提交功能,开启事务。
(3)然后执行具体的sql逻辑操作
①在操作过程中,如果执行失败了,那么会通过completeTransactionAfterThrowing来完成事务的回滚操作,回滚的具体逻辑是通过doRollBack方法来实现的,实现的时候也是先获取连接对象,通过连接对象来回滚
②如果执行成功了,那么会通过commitTransactionAfterReturning来完成事务的提交操作,提交的具体逻辑是通过doCommit方法来实现的,实现的时候也是要获取连接,通过连接对象来提交
(4)当事务执行完毕后需要清除相关的事务信息cleanupTransactionInfo

事务属性:回滚策略

(1)声明式事务默认只针对运行时(unchecked exceptions)异常回滚,编译时异常(checked exceptions)不回滚。可以通过@Transactional中相关属性设置回滚策略
(2)因为什么而回滚:
①rollbackFor属性:需要设置一个Class类型的对象
②rollbackForClassName属性:需要设置一个字符串类型的全类名
(2)因为什么而不回滚:
③noRollbackFor属性:需要设置一个Class类型的对象
④noRollbackForClassName属性:需要设置一个字符串类型的全类名

Spring事务的传播机制(事务的7种传播级别)

假如方法A执行过程中调用了方法B,方法A为当前事务:
(1)REQUIRED(Spring默认的事务传播机制)
①如果当前没有事务,则自己新建一个事务
②如果当前存在事务,则加入这个事务。
(2)SUPPORTS
①如果当前没有事务,就以非事务方法执行。
②如果当前存在事务,则加入当前事务
(3)MANDATORY
①如果当前没有事务,则抛出异常。
②如果当前存在事务,则加入当前事务
(4)REQUIRES_NEW
创建一个新事务,如果存在当前事务,则挂起该事务。
(5)NOT_SUPPORTED
以非事务方式执行,如果当前存在事务,则挂起当前事务。
(6)NEVER
不使用事务,如果当前事务存在,则抛出异常。
(7)NESTED
①如果当前没有事务,则自己新建一个事务
②如果当前事务存在,则在嵌套事务中执行

Spring事务失效的场景

(1)数据库不支持事务
(2)事务方法未被Spring管理
(3)方法没有被public修饰
(4)如果同一个类中的两个方法分别为A和B,方法A上没有添加事务注解,方法B上添加了 @Transactional事务注解,方法A调用方法B,则方法B的事务会失效。
(5)方法的事务传播机制不支持事务
(6)未配置事务管理器
(7)不正确的捕获异常
(8)在@Transactional注解中标注了错误的异常类型

Spring中的bean 是线程安全的吗?

(1)Spring容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是还是要结合具体scope(作用域)的Bean去研究。
(2)对于原型Bean,每次都创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。
(3)对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。
①如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行「查询」以外的操作,那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等,这些Bean大多是无状态的,只关注于方法本身。
②但是如果Bean是有状态的 那就需要开发人员自己来进行线程安全的保证,最简单的办法就是改变bean的作用域 把 singleton 改为 protopyte, 这样每次请求Bean就相当于是 new Bean() 这样就可以保证线程的安全了。

spring单例,为什么controller、service和dao确能保证线程安全?

(1)Spring中的Bean默认是单例模式的,框架并没有对bean进行多线程的封装处理。实际上大部分时间Bean是无状态的(比如Dao) 所以说在某种程度上来说Bean其实是安全的。
①有状态就是有数据存储功能
②无状态就是不会保存数据
(2)controller、service和dao层本身并不是线程安全的,如果只是调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。

循环依赖

Spring是如何解决循环依赖的?

采用的是三级缓存解决的,其实就是三个Map
(1)一级缓存:存储的是所有创建好了的单例Bean
(2)二级缓存:存储的是完成实例化,但是还未进行属性注入及初始化的对象。配合三次缓存避免多重循环依赖的情况,并解决重复创建动态代理问题
(3)三级缓存:存储的是 ObjectFactory<?> 类型的代理工厂对象
a.三级缓存是函数接口:通过lambda把方法传进去,其实就是把bean的实例和bean的名字传进去,后期会进行aop动态代理创建
b.但是不会立即调用(如果在实例化后立即调用,那么所有的aop不管bean是否循环依赖都会在实例化后创建动态代理。正常bean的话spring还是希望遵循生命周期在初始化后创建动态代理,只有循环依赖才创建)
c.比如说getBean(A)-getBean(B)-getBean(A),也就是第二次getBean(A)的时候才会调用三次缓存
d.把返回的对象放入二级缓存(二级缓存中存储的就是从三级缓存这个工厂中获取到的对象),避免重复创建(比如A依赖B和C,B和C依赖于A,就会创建两次A)

二级缓存能不能解决循环依赖

(1)如果只是死循环的问题:一级缓存就可以解决,但无法避免在并发下获取不完整的bean
(2)二级缓存也可以解决循环依赖:只不过如果出现重复循环依赖,会多次创建aop的动态代理

Spring有没有解决多例Bean的循环依赖

(1)多例不会使用缓存进行存储,每次使用都需要重新创建
(2)不缓存早期对象就无法解决循环依赖

Spring有没有解决构造函数bean的循环依赖

(1)没有
(2)可以通过人工进行解决:使用@Lazy注解
①就不会立即创建依赖的bean了
②而是等到用到才通过动态代理进行创建

二.Spring MVC

简单介绍下你对springMVC的理解?

是基于java的MVC设计模式的轻量级MVC框架,通过对Model、view、Controller分离,把web应用分成逻辑清晰的几部分,简化了开发,方便了开发人员的配合。
(1)M-Model(数据模型):负责操作所有数据和服务器进行交互,将请求到的数据传给Controller。
(2)V-View(视图):负责界面的显示,以及与用户的交互功能,例如表单、网页等。
(3)C-Controller(控制器):可以理解为一个分发器,用来决定对于视图发来的请求,需要用哪一个模型来处理,以及处理完后需要跳回到哪一个视图。即用来连接视图和模型

HTTP接口调用一般有哪几种传参方式?

(1)查询字符串参数(Query Parameters):参数直接附加在URL的末尾,以问号(?)开始,多个参数之间使用
与号(&)分隔。例如:https://api.example.com/users?name=John&age=25
(2)URL路径参数(Path Parameters):参数直接嵌入在URL的路径中,通常用于标识资源的唯一标识符或者指定特定的操作。例如:https://api.example.com/users/12345
(3)请求体参数(Request Body Parameters):参数作为HTTP请求的主体部分(请求体)发送,通常用于传递大量数据。常见的请求体参数格式包括JSON、XML、表单数据等。
(4)请求头参数(Request Header Parameters):参数作为HTTP请求的头部信息中的一部分发送。例如,可以使用Authorization头部字段来传递身份验证令牌。
(5)Cookie参数(Cookie Parameters):参数存储在HTTP请求的Cookie中,服务器可以通过读取Cookie来获取参数值。
(6)文件上传参数(File Upload Parameters):用于上传文件时的参数,通常以表单形式发送,可以通过请求体或者请求头来传递。

@ResponseBody作用

在RequestMapping中 return返回值默认解析为跳转路径,@ResponseBody注解可以将Controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区域,通常返回JSON数据或XML数据。

Spring MVC的主要组件?

(1)前端控制器 DispatcherServlet(不需要程序员开发)
DispatcherServlet是整个流程控制的中心,负责调用其他组件处理用户的请求,DisPatcherServlet的存在降低了组件之间的耦合度
(2)处理器映射器HandlerMapping(不需要程序员开发)
根据用户请求找到Handler处理器
(3)处理器适配器HandlerAdaptor
这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
(4)处理器Handler(需要程序员开发)
这是我们开发中要编写的具体业务控制器。由DispatcherServlet把用户请求转发到 Handler,再由Handler对具体的用户请求进行处理。
(5)视图解析器ViewResolver(不需要程序员开发)
根据视图逻辑名解析成真正的视图(view)
(6)视图view(需要程序员开发)
view是一个接口,它的实现类支持不同的视图类型(如:jsp,freemarker,pdf等等)

Spring MVC的执行流程

(1)用户发送请求到前端控制器DispatcherServlet。
(2)DispatcherServlet将请求的URL传递给处理器映射器HandlerMapping。
(3)HandlerMapping会返回handler处理器(底层返回的是处理器执行链,里面会包含拦截器以及处理器handler的信息)
(4,5)DispatcherServlet根据handler获取合适的HandlerAdapter
(6)如果有拦截器,DispatcherServlet则会调用拦截器的preHandler方法
(7,8)然后处理器适配器会调用具体的处理器(Controller)
(9,10)并返回ModelAndView对象给DispatcherServlet。
(11)如果有拦截器则执行postHandle方法
(12)然后DispatcherServlet将ModelAndView传给视图解析器ViewReslover。
(13)ViewReslover解析后返回具体视图View。
(14)DispatcherServlet根据View进行视图渲染。
(15)如果有拦截器则调用afterCompletion方法
(16)DispatcherServlet响应用户。
在这里插入图片描述

在这里插入图片描述

拦截器

拦截器的作用

SpringMVC拦截器的作用是请求到达控制器之前或之后进行拦截,可以对请求和响应进行一些特定的处理

拦截器使用的场景

(1)登录验证:对于需要登录才能访问的网址,可以使用拦截器判断用户是否登录,如果未登录则跳转到登录页面
(2)权限校验:根据用户权限对部分网址进行访问控制,拒绝未经授权的用户访问
(3)请求日志:记录请求信息,例如请求地址、请求参数、请求时间等,用于排查问题性能优化
(4)更改响应:可以对响应的内容进行修改,例如添加头信息、调整响应格式内容等

过滤器和拦截器的区别

(1)实现原理不同
①过滤器 是基于函数回调的
②拦截器 则是基于Java的反射机制(动态代理)实现的
(2)使用范围不同
①过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在Servlet规范中定义的,也就是说过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。
②而拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。不仅能应用在web程序中,也可以用于Application、Swing等程序中。
(3)触发时机不同
①过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。

拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。

拦截器在SpringMVC指向流程中的哪一步?

(1)preHandler():处理器方法调用之前,postHandler():处理器方法调用之后
详解:从所有HandlerAdapter 中找到可以处理该 Handler 的 HandlerAdapter 对象后,
执行 HandlerExecutionChain 中所有拦截器的 preHandler(),然后再利用 HandlerAdapter 执行 Handler ,执行完成得到 ModelAndView,再依次调用拦截器的 postHandler();
(2)afterCompletion():页面渲染完成后

三.MyBatis

MyBatis中#{}和${}的区别

(1)#{}是预编译处理,${}是字符串替换。
(2)MyBatis在处理#{}时,会将SQL中的#{}替换为?号,调用PreparedStatement的set方法来赋值。
(3)使用#{}可以有效的防止SQL注入,提高系统安全性。原因在于:预编译处理之后,SQL的结构已经固定,即便用户输入非法参数,也不会对SQL的结构产生影响,从而避免了潜在的安全风险。
(4)MyBatis在处理 ${}时,就是把 ${}替换成变量的值,调用Statement来赋值。典型情况就是动态参数只能使用${}
(5)注意:
①在JDBC能使用占位符的地方,最好优先使用#{}

  UPDATE t_address
        SET is_default = 0
        WHERE uid = #{uid}

②在JDBC不支持使用占位符的地方,就只能使用${},典型情况就是 动态参数
a.比如 有两张表,分别是emp_11 和 emp_22,如果需要在查询语句中 动态指定表名,就只能使用 ${}

select * from emp_ ${year}

b.再比如MyBatis 排序时使用order by 动态参数时,此时也只能使用 ${}

select * from dept order by ${name}

在MyBatis中如何传递多个参数

(1)顺序传参法:方法里面写参数,在xml文件中通过#{}里面写入数字代表你传入参数的顺序。这种方法不建议使用,sql层表达不直观,且一旦顺序调整容易出错。

public User selectUser(String name, int deptId);

<select id="selectUser" resultMap="UserResultMap">
    select * from user
    where user_name = #{0} and dept_id = #{1}
</select>

(2)使用@Param注解:#{}里面的名称对应的是注解@Param括号里面修饰的名称。这种方法在参数不多的情况还是比较直观的,推荐使用。

Integer updateDefaultByAid(
            @Param("aid") Integer aid,
            @Param("modifiedUser") String modifiedUser,
            @Param("modifiedTime") Date modifiedTime
    );

(3)Map传参法:#{}里面的名称对应的是Map里面的key名称。这种方法适合传递多个参数,且参数易变能灵活传递的情况。

public User selectUser(Map<String, Object> params);

<select id="selectUser" parameterType="java.util.Map" resultMap="UserResultMap">
    select * from user
    where user_name = #{userName} and dept_id = #{deptId}
</select>

(4)通过自定义对象传递:#{}中的名称就是自定义对象的属性名称,这种方法很直观,但是需要创建一个实体类,扩展不容易,需要添加属性,但是代码的可读性很高,业务逻辑处理也非常方案,推荐使用

public User selectUser(Map<String, Object> params);

<select id="selectUser" parameterType="com.test.User" resultMap="UserResultMap">
    select * from user
    where user_name = #{userName} and dept_id = #{deptId}
</select>

在MyBatis中如何执行批量操作

使用foreach标签
(1)foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach标签的属性主
要有item,index,collection,open,separator,close。
①item   表示集合中每一个元素进行迭代时的别名,随便起的变量名;
②index   指定一个名字,用于表示在迭代过程中,每次迭代到的位置,不常用;
③open   表示该语句以什么开始,常用“(”;
④separator 表示在每次进行迭代之间以什么符号作为分隔符,常用“,”;
⑤close   表示以什么结束,常用“)”。
(2)在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是
在不同情况下,该属性的值是不一样的,主要有一下3种情况:
① 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
② 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
③ 如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封
装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map
的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封
装的map里面的key

Mybatis动态sql是做什么的,有哪些动态sql,动态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的功能。

MyBatis的工作原理

(1)MyBatis启动加载
①SqlSessionFactory:会完成全局配置文件和映射文件的加载解析操作,然后会把相关的信息保存到
Configuration对象中。创建的SqlSessionFactory对象的实现是DefaultSqlSessionFactory对象
②SqlSession:通过SqlSessionFactory获取了SqlSession对象,创建的具体的实例是DefaultSqlSession
(2)MyBatis如何处理请求
SqlSession中提供了处理请求的方法:save select update delete
调用对应的Executor处理,如果有配置缓存处理–> 先走二级缓存,然后再走一级缓存;如果缓存中都
没有查询到对应的数据才会走数据库操作,交给StatementHandler来处理,通过ParameterHandler处理
SQL中的占位符,通过ResultSetHandler处理结果集的映射。

MyBatis中用到了哪些设计模式

(1)缓存模块:装饰者模式
(2)日志模块:适配器模式,代理模式
(3)SqlSessionFactory:工厂模式
(4)Mapper接口:代理模式
(5)SqlSessionFactoryBuilder:建造者模式

动态SQL的<foreach>标签的属性有哪些?

(1)collection:代表要遍历的集合元素,注意编写时不要写#{}
(2)open:代表语句的开始部分
(3)close:代表语句的结束部分
(4)item:代表遍历集合的每个元素,生成的变量名
(5)sperator:代表分隔符
①动态sql语句

<select id="findByIds" parameterType="list">
select * from User
	<where>
		<foreach collection="array" open="id in(" close=")" item="id" seperator=",">	
			#id
		</foreach>
	</where>
</select>

②测试

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int[] ids = new int[]{2,5};
List<User> userList = userMapper.findByIds(ids);

resultMap与resultType的区别

(1)实体类的名字和数据库相同时,可以直接设置resultType参数为pojo类

 <select id="findByParent" resultType="com.cy.store.entity.District">
        SELECT *
        FROM t_dict_district
        WHERE parent = #{parent}
        ORDER BY CODE ASC;
  </select>

(2)若不同,需要设置resultMap将查询结果集中的列一一映射到bean对象的各个属性

 <resultMap id="resultUser" type="com.cy.store.entity.User">
 		<!-- column为数据库表的字段名称,property为实体的属性名称 -->
        <result column="created_user" property="createdUser"></result>
        <result column="created_time" property="createdTime"></result>
        <result column="modified_user" property="modifiedUser"></result>
        <result column="modified_time" property="modifiedTime"></result>
 </resultMap>
<select id="findByUsername" resultMap="resultUser">
        select *
        from t_user
        where username = #{username}
  </select>

parameterType和parameterMap的区别

要想理解parameterType和parameterMap的区别
我们以下面这个mapper接口中的方法为例

 Cart findByUidAndPid(
            @Param("uid") Integer uid,
            @Param("pid") Integer pid
    );

(1)parameterType的使用
//行内参数映射

<select id="findByUidAndPid"  parameterType="java.lang.Integer">
       SELECT *
       FROM t_cart
       WHERE uid = #{uid}
         AND pid = #{pid};
   </select>

(2)parameterMap的使用
注意:要把占位符#{}改为?

 <parameterMap id="cart" type="com.cy.store.entity.Cart">
        <parameter property="uid"/>
        <parameter property="pid"/>
    </parameterMap>
     <select id="findByUidAndPid"  parameterMap="cart">
        SELECT *
        FROM t_cart
        WHERE uid = ?
          AND pid = ?;
    </select>

(3)使用场景
(1)观看上面两种方法,我们会发现使用行内参数映射比parameterMap配置看起来更直观,阅读性更强,这里只是两个参数,所以是两个?,如果我们有100个参数呢?
(2)实际上,parameterMap元素很少被使用,因为他和select|insert|update|delete元素的parameterType属性的作用类似。
而且就连parameterType属性也很少使用,因为mybatis可以通过类型处理器(TypeHandler)推断出具体传入语句的参数类型:

MyBatis四处拦截点

(1)StatementHandler拦截点:可以在 SQL 语句被发送到数据库执行前进行自定义操作,比如修改原始 SQL 语句、设置特殊的 Statement 属性等。
(2)ParameterHandler拦截点:可以在 SQL 参数绑定前后进行操作。适用于复杂的参数处理逻辑,比如数据加密/解密,或者对特殊的参数格式进行处理。
(3)ResultSetHandler拦截点:可以在结果集处理前后做一些处理。比如对结果集进行加工、转换等操作。
(4)Executor拦截点:可以在 SQL 执行前后添加逻辑,比如在查询语句执行前后添加缓存。

PageHelper实现分页的原理

(1)一次请求就是一个线程,PageHelper.startPage(page,size)中携带分页参数。分页参数会设置在ThreadLocal中。
(2)PageHelper通过拦截Executor接口中的query方法,实现对SQL语句的拦截。在拦截过程中,PageHelper会解析用户传入的分页参数,从ThreadLocal中取出分页参数,修改当前执行的sql语句,添加分页sql
(3)最后执行添加了分页的sql语句,实现分页查询

Mybatis中的执行器有哪些?如何指定我们需要的Executor类型?

(1)Mybatis中的执行器有以下三种:
①SimpleExecutor:简单的执行器,mybatis默认的执行器,每次执行操作都会开启一个新的Statement对象,用完就会立刻关闭
②ReuseExecutor:重复使用的执行器,实现了对Statement对象的复用
③BatchExecutor:批量执行器, 对相同sql进行一次预编译, 然后设置参数, 最后统一执行操作
(2)指定我们需要的Executor类型
①可以通过SqlSessionFactory中的openSession方法来指定对应的执行器类型
②也可以通过全局配置文件中的settings来配置默认的执行器

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值