面试官常问的30个SpringMVC题【附带答案】
- 1、Spring的优点是什么?
- 2、Spring是什么?
- 3、Spring框架的主要模块有哪些?
- 4、Spring框架用到了哪些设计模式?
- 5、什么是IOC?
- 6、解释IOC、DI,说明IoC和DI的关系?
- 7、你如何理解Spring AOP的?
- 8、AOP中的Aspect、Advice 、Advice Arguments、Pointcut、JoinPoint分别是什么?
- 9、请解释Spring Bean的全部生命周期?
- 10、Spring支持的Bean的作用域有哪几种?
- 11、简述MVC的工作流程
- 12、MVC的主要组件是什么?
- 13、简述Spring MVC的请求处理过程?
- 14、Spring MVC的常见注解有哪些?
- 15、Spring MVC进行传值的方式有哪些?
- 16、Spring MVC如何进行重定向和转发,他们的区别是什么?
- 17、Spring MVC如何进行乱码处理?
- 18、简述JAVA异常处理机制的简单原理和应用?
- 19、Spring MVC的拦截器应如何使用?
- 20、Spring MVC拦截器的三个方法的执行时机是什么?
- 21、什么是Mybatis?
- 22、Mybatis和Hibernate有哪些不同?
- 23、Mybatis能执行一对一、一对多的关联查询吗?有哪些实现方式?以及它们之间的区别是什么?
- 24、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
- 25、什么是事务?事务的四个特征是什么?事务的并发问题有哪些?事务的隔离级别有哪些?
- 26、Execute和executeUpdate的区别是什么?
- 27、Mybatis的一级缓存和二级缓存分别是什么?它们的区别是什么?
- 28、为什么要避免使用Mybatis的二级缓存?
- 29、Mybatis动态SQL的作用是什么?有哪些动态SQL?请简述动态SQL的执行原理?
- 30、Mybatis能执行一对一、一对多的关系查询吗?有哪些实现方式,它们之间的区别是什么?
[面试小问题解答]
假设现在有装有1元、10元、100元、1000元的红包,你和另外一个人各拿了一个红包,你们可以拆开看,但是不能让另外一个人知道,同时你们可以进行交换,如果双方都同意的话,只要有一方不愿意,就不能进行交换,同时规定两人都是理性的。
- 如果此时你拿到的是10元的红包,你觉得你应该如何决策,从而获得更大的利益?交换还是不交换?为什么?
- 假设现在是10个红包,里面分别装有1、10、100、1000…10^9的钱,你此时还是只得到10元的红包,此时你又该如果决策?从而获得更大的利益?
在上篇博文里,我们提到一个面试官常用来考察面试者的逻辑能力的小问题,这里我给出一个被大家所认可的一个答案。
参考答案
- 当对方得到1000元时,对方绝对不会做出交换的决策,那么如果对方得到100元时,他便也会这样想,如果对方得到1000元绝对不会换,那么他得到100元,做出交换便无法换到1000元,自然便不能获得比100元大的金额,所以他自然不会做出交换的决策,那么你得到了10元,自然无法获得100元与之交换,相反如果做出交换,相比得出的是与1元进行交换的事件发生,所以最后的决策是不交换便是最好的决策。
- 相比问题只是给出选择的更多可能,但是依然经不起问题的推敲,所以你获得10元,依然是不交换,而这便是最好的决策。
面试官常问的30个SpringMVC题
1、Spring的优点是什么?
- Spring属于低侵入式设计,代码污染极低。
- Spring的DI机制将对象之间的依赖关系交由框架处理,减少组件的耦合性。
- Spring提供了AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而进行更好的复用。
- Spring对于主流的应用框架提供了集成支持。
2、Spring是什么?
Spring是一个轻量级的IoC和AOP容器框架,是为了JAVA应用程序提供基础性服务的框架,目的是简化企业应用程序的开发,它使得开发者只需要关注业务需求。常见的配置方式有三种:基于XML的配置、基于注解的配置、基于JAVA的配置。
Spring主要由以下几个模块组成:
- Spring Core:核心类库,提供IoC服务。
- Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等)。
- Spring AOP:提供AOP服务。
- Spring DAO:对JDBC的抽象,简化了数据访问异常的处理。
- Spring ORM: 提供对现有ORM框架的支持。
- Spring Web:提供基础的面向Web的综合特性,例如多方文件上传
- Spring MVC:提供面向Web应用的Model-View-Controller实现。
3、Spring框架的主要模块有哪些?
- Sping Core:Sping的核心功能,使用IoC容器解决对象创建及依赖关系问题,包含并管理应用对象的配置和生命周期。
- Spring DAO:Spring 对JDBC的支持,可使用JdbcTemplate简化数据操作。
- Spring ORM:Spring对ORM的支持,提供了对主流对象映射关系框架的支持,以及与多个第三方持久层框架的良好整合。如Mybatis、Hibernate
- Spring AOP:切面编程,减少了非业务代码的重复性,降低了模块之间的耦合,如事务管理、日志、权限验证。
- Spring Web:Spring对Web模块的支持。
- Spring JEE:Spring对Java EE 其他模块的支持,如EJB,JMS等。
- Spring MVC:提供面向Web应用的Model-View-Controller实现。
- Spring Context :提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等)。
4、Spring框架用到了哪些设计模式?
- 单例模式:在Sping配置Bean时,一般默认为单例。
- 工厂模式:BeanFactory用来创建对象实例。
- 代理模式:Spring AOP(JDK动态代理,Cglib)
- 前端控制器模式:Spring提供了DispatcherServlet对请求进行处理
- 模板方式模式:减少代码重复性。
- 适配器模式:Spring AOP
- 装配器模式:Spring Data Hashmapper
- 观察者模式:Spring 时间驱动模型。
- 回调模式:Spring ResourceLoaderAware回调接口
5、什么是IOC?
- IOC即控制反转:是面向对象编程的一种设计原则,可以用来减少计算机代码之间的耦合度。其中最常见的方式叫作依赖注入
(Dependency Injection,DI)
,还有一种方式叫作依赖查找(Dependency Lookup)
,例如audit==(AuditService)ctx.lookup("java:com/env/audit");
。 - Spring IoC:从微观方面来讲,
Spring IoC
就是一个````ConcurrentHashMap,存放对象的名字和实例。从宏观方面来讲,
Spring IoC就是
Spring的环境,包括
Spring的
Bean```工厂、注册器、读取器等。
6、解释IOC、DI,说明IoC和DI的关系?
- IoC:把对象的创建、初始化、销毁交给Spring框架来管理、而不是由程序控制,实现控制反转。
- DI:依赖注入,在Spring创建对象的过程中,将对象依赖属性通过配置进行注入,DI可以通过Setter方法注入(设值注入)、构造方式注入和注解注入三种方式来实现。
- 使用构造方式注入时,先实例化依赖的对象后,才实例化原对象。而使用Setter方式注入时,Spring首先实例化对象,然后才实例化所有依赖的对象。
- 当Setter方式注入与构造方式注入同时存在时,先执行Setter方法注入,再执行构造方式注入。
- IoC和DI的关系:IoC是需要实现的目标,DI是实现IoC的一种技术手段。
7、你如何理解Spring AOP的?
AOP一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑抽取出来并封装为一个可重用的模块,这个模块被命名为切面。AOP的使用有助于减少系统中的重复代码,降低模块间的耦合度,同时提高系统的可维护性,可用于权限认证、日志、事务处理。
AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ,动态代理则以Spring AOP为代表。
- AspectJ是静态代理的增加。所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增加,它会在编译阶段将AspectJ(切面)织入Java字节码中,运行的就是增强后的AOP对象。
- Spring AOP使用的是动态代理。所谓的动态代理,就是AOP框架不会修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,在特定的切点做了增强处理,并调用原对象的方法。
8、AOP中的Aspect、Advice 、Advice Arguments、Pointcut、JoinPoint分别是什么?
- Aspect:Aspect是一个实现交叉问题的类,例如事务管理。Aspect可以是配置的普通类,可以在SpringBean配置文件中配置。Spring AspectJ支持使用@Aspect注解将类声明为Aspect
- Advice:Advice是针对特定的JoinPint采取的操作。在编程方面,它们是应用程序中达到具有匹配切点的特定JoinPoint时执行的方法。可以将Advice视为Spring拦截器或Servlet过滤器。
- Advice agruments:可以在Advice方法中传递参数。我们可以在切点中使用args()表达式来应用于参数模式匹配的任何方法。如果使用它,那么需要在确定参数类型的Advice方法中使用相同的名称。
- Pointcut:pointcut是与JoinPoint匹配的正则式。用于确定是否需要执行Advice。pointCut使用与JoinPoint匹配的不同类型的表达式。spring框架使用AspectJ Pointcut表达式语言来确定将应用通知方法的JoinPoint。
- JoinPoint:JoinPoint是应用程序中的特定点,例如方法执行、异常处理、更改对象变量值等。在Spring AOP中,JoinPoint始终是方法的执行器。
补充:Spring AOP的五种通知类型:
- 环绕通知(@Around):是指环绕一个连接点(比如方法调用)的通知,是最强的一种通知。环绕通知可以在方法调用之前或之后执行自定义的行为,环绕通知也可以选择是否要处理连接点方法的执行,通过返回一个值或者直接抛出异常。环绕通知是使用最普通的一种通知。
- 前置通知(@Before):是指在一个连接点之前执行的通知。前置通知没有能力阻止的后面的执行(除非他抛出异常),也就是说在执行目标方法之前运行。
- 返回通知(@After(finally)):是指在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容。
- 异常返回通知(@AfterThrowing):是指如果方法因为抛出异常而退出了才会执行的通知,也就是说在目标方法出现异常后执行。
- 正常返回通知(@AfterReturning):是指在连接点正常执行完成后执行的通知,如果连接点抛出异常,则不会执行。
9、请解释Spring Bean的全部生命周期?
Servlet的生命周期包括实例化、初始化INT、接收请求Service、销毁Destory。Spring Bean的生命周期类似。
- 实例化Bean:对于BeanFactory容器,当客户向容器请求一个尚未初始化的Bean时,或初始化Bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用CreateBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的Bean。
- 设置对象属性(依赖注入):实例化后的对象被封装在BeanWrapper对象中,然后Spring根据BeanDefinition中的信息并通过BeanWrapper提供的设置属性的接口完成依赖注入.
- 处理Aware接口:Spring会检测该对象是否实现了xxxAwar接口,并将相关的xxxAware实例注入Bean。
1、如果这个Bean已经实现BeanNameAware接口,会调用它实现setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的ID值。
2、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
3、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplcationContext(ApplicationContext)方法,传入Spring上下文。
- BeanPostProcessor:如果想对Bean进行一些自定义的处理,可以让Bean实现BeanPostProcessor接口,则将调用postProcessBeforeIntization(Object obj,String s)方法。由于这个方法是在Bean初始化结束调用的,所以可以被应用于内存或缓存技术。
- InitializingBean与Init-Method:如果Beanzai Spring配置文件中配置了Init-Method属性,则会自调用配置的初始化方法。
- 如果这个Bean实现了BeanPostProcessor接口,则调用postProcessAfterInitialization(Object obj,String s)方法。
- DisposableBean:当Bean不再需要时,会经过清理阶段。如果Bean实现了DisposableBean这个接口,则会调用其实现的destory()方法。
- Destory-Method:如果这个Bean的Spring中配置了Destory-Method属性,则会自动调用其配置的销毁方法。
10、Spring支持的Bean的作用域有哪几种?
- Singleton:这是默认Scope,表示在整个Bean容器中或者整个应用中只会有一个实例。
- Prototype:多例类型,表示每次都会从Bean容器中获取一个对应Bean定义的全新实例。
- Request:仅适用于Web环境下的ApplicationContext,表示每个HttpSession生命周期内会有一个单独的实例,即每个一个HTTP请求都会拥有一个单独的实例。
- Session:仅适用于Web环境下的ApplicationContext,表示每个HttpSession生命周期内会有个单独的实例,即每一个HttpSession下都会拥有一个单独的实例,即每一个用户都将拥有一个单独的实例。
- GlobalSession:仅适用于Web环境下的AppllicationContext,一般来说是Portlet环境下,表示每一个全局的HttpSession下都会拥有一个单独的实例。
11、简述MVC的工作流程
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用HandlerMapping处理器映射器
- 处理器映射器根据请求URL找到具体的处理器,生成处理器对象及处理器拦截器,一并返回给DispatcherSerlet
- DispatcherServlet通过HandlerAdapter处理器适配器调用处理器。
- 执行控制器Controller
- Controller执行完毕返回ModelAndView
- HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover解析后返回具体View
- DispatcherServlet对View进行渲染视图,即将模型数据填充至视图汇中。
- DispatcherSerlet响应用户。
12、MVC的主要组件是什么?
- 前端控制器(DispatcherServlet)
- 处理器映射器(HandlerMapping)
- 处理器适配器(HandlerAdapter)
- 处理器(Handler)
- 视图解析器(ViewResolver)
- 视图(View):View是一个接口,它的实现类支持不同的视图类型,例如JSP、freemarker、pdf等。
13、简述Spring MVC的请求处理过程?
- 用户向服务器发送请求,请求被Spring MVC前端控制器(DispatcherServlet)捕获。
- 前端控制器对请求URL进行解析,得到请求资源标识符(URL),然后根据该URL调用页面处理器(HandlerMapping)获得该Handler配置的所有相关对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExcecutionChain对象的形式返回。
- 前端控制器根据获得的Handler选择一个合适的HandlerAdapter适配器处理。
- Handler对数据处理完成以后将返回一个ModelAndView()对象给前端控制器。
- Handler返回的ModelAndView()只是一个逻辑视图,并不是一个正式的视图,前端控制器通过ViewResolver视图解析器将逻辑视图转化为真正的视图View。
- DispatcherServlet通过Model解析出ModelAndView()中的参数,最终展现完整的View并返回给客户端。
14、Spring MVC的常见注解有哪些?
- @requestMapping:用于请求URL映射
- @RequestBody:实现接收HTTP请求的JSON数据,将JSON数据转换为JAVA对象。
- @ResponseBody:实现将Controller方法返回对象转化为JSON响应给客户。
- @Conntroller:控制器的注解,表示是表现层,不能用其他注解代替。
15、Spring MVC进行传值的方式有哪些?
(1)、页面传值到控制器有三种方式:
- 使用Request传值的特点:直接,但是不能自动进行类型转换。
- 通过属性传值的特点:
第一、变量名必须和表单组件的name值相同
第二、可以实现类型转换
第三、进行类型转换时可能会出现异常 - 使用Bean对象传值的特点:
第一、如果前端提交数据过多,建议使用此方式
第二、把表单组件的name属性值封装到Bean类中,
第三、方法的参数传递封装类型的对象即可
(2)、控制器传值到页面有三种方式:
- 使用Request和Session对象
- 使用ModelAndView传值的特点:
第一、可以在ModelAndView构造方法中设置一个Map对象
第二、Map对象经过框架处理后,会把key-value设置到Request对象中。 - ModelMap传值的特点:
第一、ModelMap是框架提供的Map集合
第二、ModelMap同样被框架设置到Request对象中。
16、Spring MVC如何进行重定向和转发,他们的区别是什么?
- 重定向是指服务通知浏览器向一个新的地址发送请求
response.sendRedirect(String s) ;
特点:
- 重定向地址是任意的
- 重定向之后,浏览器地址栏的地址会发生改变
- 转发是指一个Web组件将未完成的处理交给另一个Web组件进行完成。
rd.forward(request ,response) ;
特点:
- 转发之后,浏览器地址栏的地址不变。
- 转发的目的地必须是同一个Web应用中的某个地址。
- 重定向和转发的区别如下:
- 是否共享Request对象:转发可以,而重定向不行
- 地址栏的地址有无变化:转发不变,重定向会变
- 目的地有无限制:转发有限制,重定向没有限制
17、Spring MVC如何进行乱码处理?
- 对于POST乱码,在web.xml文件中添加POST乱码过滤器——
CharacterEncodingFilter
- 对于GET请求中文参数出现乱码的情况,解决方案:
(1)、修改Tomcat配置文件,添加编码与工作编码一致<Connector URLEncoding="utf-8" connectionTimeout="2000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
(2)、对参数进行重新编码String userName=new String(request.getParamter("username".getBytes("ISO8859-1","utf-8")))
ISO8859-1是Tomcat默认编码,需要将Tomcat
编码后的内容按utf-8编码。
18、简述JAVA异常处理机制的简单原理和应用?
异常是指JAVA程序运行时(非编译)发生的非正常情况或错误。与现实生活中的事件很相似,现实生活中的事件可以包含事件发生的时间、地点、人物、情节等信息。可以用一个对象来表示。Java使用面向对象的方式来处理异常,它把程序中发生的每个异常分别封装到一个对象中,该对象中包含异常的信息。
Java对异常进行了分类,不同类型的异常分别用不同的JAVA类表示。所有异常类的根类为java.lang.Throwable
,Throwable下面又派生两个子类:Error
和Exception
,Error表示应用程序本身无法克服和恢复的严重问题,例如内存溢出和线程死锁等系统问题。Exception
表示程序还能克服和恢复的问题,其中又分为系统异常和普通异常。系统异常是程序本身的缺陷所导致的问题,也就是程序开发人员考虑不周所导致的问题。程序使用者无法克服和恢复这种问题,但出现这种问题时可以让程序继续运行或者让程序停止运行,例如数组脚本越界、空指针异常、类转换异常;普通异常是运行环境变化或异常所导致的问题,是用户能克服的问题,网络断线、硬盘空间不够、发生这样的异常后,程序不应停止运行。
Java为系统异常和普通异常提供了不同的解决方案,编译器强制普通异常必须使用try....catch
处理或用Throws
声明继续抛给上层调用方法处理,所以普通异常又称为Checked
异常,而系统异常可以处理也可以不处理,编译器不强制使用Try.....Catch
处理或用Throws
声明,所以系统异常又称为Unchecked
异常。
19、Spring MVC的拦截器应如何使用?
定义拦截器,实现HandlerInterceptor接口,接口中提供三个方法
- preHandle:在进入
Handler
方法之前执行,用于身份认证、身份授权。例如进行身份认证,如果认证通过则表示当前用户没有登录,需要此方法拦截不再向下执行。 - postHandler:在进入
Handler
方法之后,返回ModelAndView
之前执行,应用场景从ModelAndView
出发,将公用的模型数据(如菜单导航)在这里传到视图,也可以在这里统一指定视图。 - afterCompletion:
Handler
执行完成之后执行此方法,应用场景包括统一异常处理、统一日志处理。
拦截器配置如下:
- 针对HandlerMapping配置(不推荐):SpringMVC拦截器针对HandlerMapping进行拦截设置,如果在某个
HandlerMapping
中配置拦截,经过HandlerMapping映射成功的Handler最终使用该拦截器。 - 类似全局的拦截器:
SpringMVC
配置类型全局的拦截器,SpringMVC框架将配置的类似全局的拦截器注入每个HandlerMapping
中。
20、Spring MVC拦截器的三个方法的执行时机是什么?
- 当两个拦截器都实现放行操作时,顺序为
preHanle1、preHandle2、postHandle2、postHandle1、afterCompletion2、afterCompletion1;
- 当第一个拦截器preHandle返回false,也就是对其进行拦截时,第二个拦截器是完全不执行的,第一个拦截器只执行preHandle部分。
- 当第一个拦截器
preHandle
返回True,第二个拦截器preHandle
返回false,顺序为preHandle1、preHandle2、afterCompletion1
21、什么是Mybatis?
1.Mybatis
是一个半ORM
(对象关系映射)框架,它内部封装了JDBC
,开发时只需要关注SQL
语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement
、执行SQL
等繁杂的过程,程序开发人员直接编写原生态SQL
,可以严格控制SQL
执行性能,灵活度高。
2. Mybatis
可以使用XML
或者注解来配置和映射原生信息,将POJO
映射成数据库中的记录。避免了几乎所有的JDBC
代码和手动配置参数以及获取结果。
3. 通过XML
文件或注解的方式将要执行的各种statement
配置起来,并通过JAVA
对象和statement
中SQL
的动态参数进行映射生成最终执行的SQL
语句,最后由mybatis
框架执行SQL
将结果映射为Java
对象并返回。
22、Mybatis和Hibernate有哪些不同?
-
Mybatis
和Hibernate
不是同一个ORM
框架,因为Mybatis需要程序开发人员自己编写SQL
语句。 -
Mybatis
直接编写原生态SQL
,可以严格控制SQL
执行性能,灵活度高,非常适合开发对关系型数据模型要求不高的软件,因为这类软件需要需求变化频繁,一旦需求变化则要求迅速输出成果。但是灵活的前提是mybatis
无法做到数据库无关,如果需要实现支持多种数据库的软件,则需要自定义多套SQL
映射文件,工作量大。 -
Hibernate
对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用Hibernate
开发可以节省很多代码,提高效率。
23、Mybatis能执行一对一、一对多的关联查询吗?有哪些实现方式?以及它们之间的区别是什么?
- Mybatis不仅可以执行一对一、一对多的关联查询,还可以执行多对一、多对多的关联查询。
- 多对一查询:其实就是一对一查询,只需要把
selectOne()
修改为selectList()
即可。 - 多对多查询:其实就是一个一对多查询,只需要把
selectOne()
修改为selectList()
即可。 - 关联对象查询有两种实现方式:一种是单独发送一个SQL语句去查询关联对象、赋给主对象,然后返回主对象;另一种是使用嵌套查询,嵌套查询的含义是使用JOIN查询,一部分列关联对象A的属性值,另一个部分列关联对象B的属性值,好处是只发送一个SQL查询,就可以把主对象和其关联对象查出来。
24、Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?
- Mybatis仅支持
ssociation
关联对象和Collection
关联集合对象的延迟加载,Association就是指一对一,Collection就是指一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnable=true|false
。 - Mybatis实现延迟加载的原理是使用Cglib创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用
a.getB().getName()
,拦截器invoke()
方法发现a.getB()
是null值,那么就会单独发送事先保存好的查询关联B对象的SQL,把B查询出来,然后调用a.getB(b)
,于是a的对象b属性就有值了,接着完成a.getB().getName()
方法的调用。这就是延迟加载的基本原理。(几乎所有的框架,包括Hibernate
,支持延迟加载的原理都是一样的)
25、什么是事务?事务的四个特征是什么?事务的并发问题有哪些?事务的隔离级别有哪些?
事务是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作。这些操作作为一个整体一起向系统提交、要么执行、要么都不执行。事务是一组不可分割的操作集合(工作逻辑单元)。
事务的四大特性:
- 原子性:事务是数据库的逻辑(最小)工作单元,事务中包含的各种操作要么都做,要么都不做。
- 一致性:事务执行的结果必须是使数据库从一个一致状态变到另一个一致状态,因此当数据库只包含成功事务提交的结果时,就说数据库处于一致状态。如果数据库系统运行过程中发送故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。
- 隔离性:一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各种事务之间不能互相干扰。
- 持续性(永久性):指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的,接下来的其他操作或故障不应该对其他执行结果有任何影响。
事务并发问题:
- 脏读(Dirty read):当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
- 丢失修改(Lost to modify):一个事务读取一个数据时,另一个事务也访问了该数据,那么在第一事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。
- 不可重复读(Unrepeatableread):指在一个事务内多次读同一个数据。在这个事务还没有结束时,另一个事务也访问该数据。在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样,这就发生了在一个事务内两次读到的数据不一样的情况,因此称为不可重复读。
- 幻读(phanton read):幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
事务隔离级别:
事务隔离级别 | 丢失修改 | 脏读 | 不可重复读 | 幻读 |
读未提交 | 解决 | 出现 | 出现 | 出现 |
不可重复读 | 解决 | 解决 | 出现 | 出现 |
可重复读 | 解决 | 解决 | 解决 | 出现 |
串行化 | 解决 | 解决 | 解决 | 解决 |
26、Execute和executeUpdate的区别是什么?
(1)、 相同点:两者都能够执行增加、删除、修改等操作
(2)、不同点:
- Execute可以执行查询语句,然后通过getResult把结果取出来。executeUpdate不能执行查询语句。
-
Executefanhui Boolean
类型,True表示执行的是查询语句,False表示执行的是Insert、Update、Delete
等语句。executeUpdate
返回值是int
,表示有多少条数据受到影响。
27、Mybatis的一级缓存和二级缓存分别是什么?它们的区别是什么?
- 一级缓存:基于
PrepetualCache
的HashMap
本地缓存,其存储作用域为Session,当Session flush或close
之后,该Session中的所有缓存将被清空,默认打开一级缓存。 - 二级缓存:与一级缓存机制相同,二级缓存默认也采用
PerpetualCache
的默认HashMap
存储,不同之处在于其存储作用域为Mapper(namespace)
,并且可自定义存储源,如Ehcache
。默认不打卡二级缓存,要开启二级缓存,需要使用二级缓存属性类实现Serializable
序列化接口(可用来保存对象的状态),可在它的映射文件中配置 - 对于缓存数据更新机制,当某一个作用域
(一级缓存 Session/二级缓存 namespaces)
进行创建、修改和删除操作后,默认该作用域下所有命中的缓存将被清空。
一级缓存与二级缓存的区别:
- 一级缓存基于
SqlSession
默认开启,在操作数据库时需要构造SqlSession对象,在对象中有一个HashMap用于存储缓存数据,不同SqlSession之间的数据缓存区域是互相不影响的。 - 一级 缓存的作用域是SqlSession范围内,当在同一个SqlSession中执行两次相同的SQL语句时,第一次执行完毕会将数据表中查询的数据写到缓存(内存),第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。需要注意的是,如果sqlSession执行了DML操作(增、删、改),并且提交到数据库,Mybatis则会清空SqlSession中的一级缓存。这样做的目的是保证缓存中存储的是最新的消息,避免出现脏读现象
- 当一个SqlSession结束后,该SqlSession中的一级缓存也就不存在了。关闭一级缓存后,再次访问,需要再次获取一级缓存,然后才能查询数据,否则会抛出异常。
- 二级缓存是Mapper级别的缓存。使用二级缓存时,多个SqlSession使用同一个Mapper的SQL语句去操作数据库,得到的数据存在二级缓存区域内,它同样是使用HashMap进行数据存储,二级缓存是跨SqlSession的。
- 二级缓存的作用域是Mapper的同一个namespace。不同的SqlSession两次执行相同的namespace下的SQL语句,且向SQL中传递的参数也相同,即最终执行相同的SQL语句,则两次执行完毕会将数据库中查询的数据写到缓存中,第二次查询会从缓存中获取数据,不再去底层数据库查询,从而提高效率。
28、为什么要避免使用Mybatis的二级缓存?
- 在符合Mybati二级缓存的场景使用要求时,使用二级缓存并没有什么危害,其他情况下使用二级缓存就会有很多危害了,例如
UserMapper.xml
中很多针对user表的操作,但是在一个XXXMapper.xml
中,还有针对user单表的操作,这会导致user在两个命名空间下的数据不一致。如果在UserMapper.xml
中做了刷新缓存的操作,在XXXMapper.xml
中缓存乃有效,如果有针对user单表的查询,使用缓存查询结果可能会不正确。 -
XXXMapper.xml
做了insert、update、delete
操作之后,会导致UserMapper.xml
中的各种操作充满未知和风险。
29、Mybatis动态SQL的作用是什么?有哪些动态SQL?请简述动态SQL的执行原理?
- Mybatis动态SQL可以在XML映射文件内,以标签的形式编写动态SQL,完成逻辑判断和动态拼接SQL的功能。
- Mybatis提供9种SQL标签:
trim、where、set、foreach、if、choose、when、otherwise、bind
。 - 动态SQL的执行原理是首先根据SQL参数对象计算表达式的值,然后更具表达式的值动态拼接SQL,以此完成动态SQL的功能。
<select id=""findUserById" resultType="user">
select * from user where
<if test="id !=null">
id=#{id}
</if>
and deleteFlag=0;
</select>
注释: Mybatis中的"$“与”#":
- #: 相当于对数据加上双引号;$: 相当于直接显示数据;
- #{}:根据参数的类型进行处理,比如传入String类型,则会为参数加上双引号。#{}传参在进行SQL编译时,会把参数部分用一个占位符?替代,这样可以防止SQL注入。
- ${} :将参数取出不做任何处理,直接放入语句中,就是简单的字符串替换,并且该参数会参加SQL的预编译,需要手动过滤参数防止 SQL注入。
- mybatis 中优先使用 #{};当需要动态传入表名或列名时,再考虑使用 ${}
30、Mybatis能执行一对一、一对多的关系查询吗?有哪些实现方式,它们之间的区别是什么?
- Mybatis不仅可以执行一对一、一对多的关联查询,还可以执行多对一、多对多的关联查询。
- 多对一查询:其实就是一对一查询,只需要把selectOne()修改为selectList()即可。
- 多对多查询:其实就是一个一对多查询,只需要把selectOne()修改为selectList()即可。
- 关联对象查询有两种实现方式:一种是单独发送一个SQL语句去查询关联对象、赋给主对象,然后返回主对象;另一种是使用嵌套查询,嵌套查询的含义是使用JOIN查询,一部分列关联对象A的属性值,另一个部分列关联对象B的属性值,好处是只发送一个SQL查询,就可以把主对象和其关联对象查出来。
注释:JOIN查询100条记录,如何确认主对象是5个,而不是100个?
Mybatis去重原理:<resultMap>
标签内的<id>
子标签指定了唯一确定一条记录的ID列,Mybatis根据<id>
指定的ID列值去完成100条记录的去重功能。<id>
子标签可以有多个,代表了联合主键的语意。同样,主对象的关联对象也是根据这个原理去重复的,尽管一般情况下只有主对象会有重复记录,关联对象一般不会重复查询。