- Spring
- Spring是什么
- Spring的组成,优缺点及应用场景(浅谈)
- 谈谈你对IoC的理解
- IoC能做什么(杂谈)
- DI 依赖注入
- 如何实现一个IoC容器?讲我之前手写IoC的经历
- 谈谈你对AOP的理解
- AOP有哪些可用的实现
- 谈谈你对切面的理解
- BeanFactory和ApplicationContext区别
- BeanFactory和FactoryBean的区别
- 将一个类声明为Spring的 bean 的注解有哪些?
- @Autowired和@Resource区别
- 为什么有了@Component还要用@Bean?这个注解如何实现Bean的注入?
- @Component和@Bean的区别是什么
- 浅谈BeanDefinition 因为下题会用
- 描述一下SpringBean 的生命周期 重点难点
- Spring支持的几种bean的作用域
- Spinrg框架中的单例Bean是线程安全的么
- Spring如何处理线程并发问题?
- Spring框架中设计模式
- Spring有几种配置方式?
- Spring事务的实现方式和原理以及隔离级别
- Spring事务传播机制
- Spring事务什么时候会失效
- Spring数据如何实现回滚
- 什么是bean的自动装配,有哪些方式
- SpringBoot、SpringMVC和Spring有什么区别
- Spring循环依赖的产生?如何解决?
- Spring 三级缓存
- SpringMVC
- MyBatis
- 其他小知识点
这三个我学的比较快,所以很多概念稍微写多点。
- Spring学习的尚硅谷的课 还有楠哥的课
- SpringMVC和MyBatis都是学的楠哥的快速上手课程
以下内容参考了:
https://blog.csdn.net/ThinkWon/article/details/104397516?utm_source=app&app_version=4.5.3
Spring
Spring是什么
Java 对象 很多 Spring管理对象
- 是一个轻量级Java开发框架,用来解决企业级应用开发的复杂性,简化Java开发。
- Spring可以做很多事情,这依赖于他的两个核心特性。
- 依赖注入(dependency injection DI)和面向切面编程(aspect-oriented programming AOP)
- 核心:通过DI和IoC实现解耦,通过AOP以动态非侵入的方式增强服务
Spring的组成,优缺点及应用场景(浅谈)
- 优点:方便解耦、AOP切面编程、声明式事务、方便测试、集合了其他框架、降低JavaEE使用难度。
- 缺点: 依赖反射,反射影响性能,门槛高学习成本高,轻量级框架但是大而全
- 应用场景:JavaEE企业应用开发,包括SSH、SSM等,也是SpringBoot的基础。
谈谈你对IoC的理解
在平时的java应用开发中,我们要实现某一个功能或者说是完成某个业务逻辑时至少需要两个或以上的对象来协作完成,在没有使用Spring的时候,每个对象在需要使用他的合作对象时,自己均要使用像new object() 这样的语法来将合作对象创建出来,这个合作对象是由自己主动创建出来的,创建合作对象的主动权在自己手上,自己需要哪个合作对象,就主动去创建,创建合作对象的主动权和创建时机是由自己把控的,而这样就会使得对象间的耦合度高了,A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起,而使用了Spring之后就不一样了,创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到一个容器里面,当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题(你是什么时候生的,怎么生出来的我可不关心,能帮我干活就行),A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。
所以控制反转IoC(Inversion of Control)是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。
这是我对Spring的IoC(控制反转)的理解。DI(依赖注入)其实就是IOC的另外一种说法,控制的什么被反转了?就是:获得依赖对象的方式反转了。
IoC能做什么(杂谈)
IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是 松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。
IoC很好的体现了**面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找**。
**
DI 依赖注入
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。
那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。
理解了IoC和DI的概念后,一切都将变得简单明了,剩下的工作只是在spring的框架中堆积木而已。
如何实现一个IoC容器?讲我之前手写IoC的经历
手写IoC步骤说一下:
- 先写ApplicationContext接口和实现类
- ClassPathXmlApplicaitonContext实现类
- 解析xml来获取id和全类名
- 通过id和全类名用反射途径造对象
- 通过xml里面的属性信息通过反射给对象注入属性
- 加载配置文件,解析成 BeanDefinition 放在 Map 里。
- 调用 getBean 的时候,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,如果有依赖关系,将递归调用 getBean 方法 —— 完成依赖注入。
还有循环依赖,属性注入,这就比较复杂
谈谈你对AOP的理解
我的理解:AOP是对传统OOP的补充,AOP主要的编程对象是切面。
IoC解决了对象依赖间的纵向的关系,AOP则是解决了行为间的横向关系。
AOP有哪些可用的实现
- 使用AspectJ 注解风格
- 使用Spring XML 配置风格
谈谈你对切面的理解
说说你对切面的理解?
描述切面必须先了解以下几个概念:
1.目标类:需要被增强的类。
2.连接点:可能被增强的点,目标类中的所有方法。
3.切入点:将会被增强的连接点,目标类中被增强的方法。
4.通知/增强:对切入点增强的内容。增强的内容通常以方法的形式体现的。增强执行的位置不同,称呼不同。(前置通知、后置通知、环绕通知、抛出异常通知、最终通知)
通知方法所在的类,通常称为切面类。
5.切面:通知和切入点的结合。一个通知对应一个切入点就形成一条线,多个通知对应多个切入点形成多条线,多条线形成了一个面,我们称为切面。
BeanFactory和ApplicationContext区别
他俩是干啥的不要忘记
- BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。(Spring创始人设计的两个容器)
- BeanFactory 简单粗暴,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”。
- ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具备了更多的功能。例如资源的获取,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等待。
BeanFactory和FactoryBean的区别
- BeanFactory是一个IOC工场,用于管理和创建Bean,它是IOC最基本的接口,为其他的IOC工场提供规范
- FactoryBean是一个bean,也是一个接口。FactoryBean 接口提供三个方法,用来创建对象,FactoryBean 具体返回的对象是由getObject 方法决定的。
将一个类声明为Spring的 bean 的注解有哪些?
我们一般使用 @Autowired 注解自动装配 bean,要想把类标识成可用于 @Autowired 注解自动装配的 bean 的类,采用以下注解可实现:
- @Component :通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于拿个层,可以使用@Component 注解标注。
- @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
- @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。
- @Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。
补充:基于注解方式实现对象的创建
- 引入依赖AOP.jar
- 开启组件扫描
- 引入名称空间
- 配置文件中开启组件扫描
- 创建类,再累上面添加注解(上述四种)
@Autowired和@Resource区别
同:
- @Resource和@Autowired注解都是用来实现依赖注入的。
不同:
- @AutoWried按by type自动注入;这个注解来源于Spring,要想byName需要与@Qualifier(“对象名”)连用;
- 而@Resource默认按byName自动注入。注解来源于J2EE
为什么有了@Component还要用@Bean?这个注解如何实现Bean的注入?
- 如果你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component注解的,因此就不能使用自动化装配的方案了,但是我们可以使用@Bean,当然也可以使用XML配置。
- @Bean是Spring3.0出现的,@Bean作用于方法,用来配合@Configuration使用|@Bean 需要在配置类中使用,即类上需要加上@Configuration注解
@Component和@Bean的区别是什么
- 作用对象不同: @Component 注解作用于类,而@Bean注解作用于方法。
- @Component通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了Spring这是某个类的示例,当我需要用它的时候还给我。
- @Bean 注解比 Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。
浅谈BeanDefinition 因为下题会用
在网上看到一个评论觉得不戳:
就相当于把类的代码拆解出来封装到BeanDefinition,然后就可以任意修改了。
描述一下SpringBean 的生命周期 重点难点
总的来说一句话 这个问题不能深究。
https://www.bilibili.com/video/BV1KC4y1t7x4?p=2&spm_id_from=pageDriver
首先理解一个概念
BeanFactory后置处理器(PostProcessor)是BeanFactory组建完成后执行的。
Bean后置处理器是Bean对象创建后执行的,包括填充属性,初始化、AOP功能
总体分为四个阶段:
- 实例化 CreateBeanInstance
- 属性赋值 PopulateBean
- 初始化 Initialization
- 销毁 Destruction
12解析类得到BeanDefinition,推断构造方法——->插入BeanFactoryPostProcessor BeanFactory后置处理器(就像上图一样,可以对BeanDefinition进行setScope、setBeanClass等——>3根据BeanDefinition进行实例化—->4@Autowired填充属性——>5Aware回调方法——>67调用BeanPostProcessor初始化——>8可选AOP(要是有AOP逻辑单例池就是放的代理对象了)——->9放入单例池(concurrenthashmap
10ApplicaitonContext.getBean()得到Bean——->11Spring容器关闭调用destory()
下图展示了第五步是啥意思,BeanFactoryAware同理,找自己是由哪一个BeanFactory工厂创建的。
下图展示了第六步,调用BeanPostProcessor的初始化方法就有点像我们在XML中写<init-method>
Spring支持的几种bean的作用域
Spinrg框架中的单例Bean是线程安全的么
scope字段默认单例
Spring如何处理线程并发问题?
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。<br /> ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。<br /> ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
Spring框架中设计模式
Spring有几种配置方式?
参考https://blog.csdn.net/qq_35744081/article/details/94986758
将Spring配置到应用开发中有一下三种方式:
- 基于XML的配置
- 在配置文件applicationContext.xml上写
- 在要用bean的地方new ApplicationContext
- 在配置文件applicationContext.xml上写
- 基于注解的配置
- 在bean的上面使用@Component或其子类(@Repository、@Service\@Controller)来定义bean
- 在要用bean的地方用@Autowired自动装配
- 基于Java的配置(SpringBoot推荐)
- @Configuration,表示修饰的类可以作为bean的来源(通过注解来获取bean)
Spring事务的实现方式和原理以及隔离级别
管理事务的方式:
- 编程式事务,在代码中硬编码(不推荐使用)
- 声明式事务,在配置文件中配置(推荐使用)
- 基于XML的声明式事务
- 基于注解的声明式事务
事务的隔离级别
- 默认级别:使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
- 读未提交: 最低的隔离级别,允许读取尚未提交的数据变更,
- 读已提交READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
- 可重复读: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- 可串行化: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
Spring事务传播机制
Spring事务什么时候会失效
Spring数据如何实现回滚
使用@Transactional
注解实现事务回滚
- 步骤1:在xml中配置id为transactionManager的
- 步骤2:
- 使用@Transactional注解在service,controll层都可以
- @Transactional只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能。
什么是bean的自动装配,有哪些方式
Bean的自动装配是Spring满足bean依赖的一种方式。
Spring会在上下文中自动寻找,并自动给bean装配属性。
方式:xml配置文件中autowire属性 5种 | @autowired自动装配
SpringBoot、SpringMVC和Spring有什么区别
Spring循环依赖的产生?如何解决?
https://www.yuque.com/renyong-jmovm/kb/dpzl6u 周瑜老师永远的神
A Bean创建—>依赖了B属性(是一个B类)—->触发 B Bean的创建—-> B依赖了A属性(是一个A类)——>需要A Bean(但A Bean还在创建之中)。
Spring中,用三级缓存帮助开发者解决了部分循环依赖问题
为什么只能解决部分!!!!因为二级缓存的原始对象生命周期没有走完,如果后面在BeanPostProcessor 对Bean加工(类似于AOP成了代理对象),那么极有可能注入给B对象的A对象和经历过完整生命周期的A对象不是一个对象。
Spring 三级缓存
- 一级缓存singletonObjects:缓存的是已经经历了完整生命周期的bean对象。
- 二级缓存earlySingletonObjects:比一级缓存多了一个early,表示缓存的是早期的bean对象(生命周期没走完)
- 三级缓存singletonFactories:缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的。(如果某个原始对象经过AOP了,就从这里取)
SpringMVC
https://blog.csdn.net/cx521600/article/details/90241944?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161642808816780271511497%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=161642808816780271511497&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-2-90241944.first_rank_v2_pc_rank_v29&utm_term=springMVC%E5%B8%B8%E9%97%AE%E9%9D%A2%E8%AF%95%E9%A2%98
SpringMVC的工作流程
- DispatcherServlet:前置控制器,是整个流程控制的核心,控制其他组件的执行,进行统一调度,降低组件之间的耦合性,相当于总指挥。
- Handler:处理器,完成具体的业务逻辑,相当于 Servlet 或 Action。
- HandlerMapping:DispatcherServlet 接收到请求之后,通过 HandlerMapping 将不同的请求映射到不同的 Handler。
- HandlerInterceptor:处理器拦截器,是一个接口,如果需要完成一些拦截处理,可以实现该接口。
- HandlerExecutionChain:处理器执行链,包括两部分内容:Handler 和 HandlerInterceptor(系统会有一个默认的 HandlerInterceptor,如果需要额外设置拦截,可以添加拦截器)。
- HandlerAdapter:处理器适配器,Handler 执行业务方法之前,需要进行一系列的操作,包括表单数据的验证、数据类型的转换、将表单数据封装到 JavaBean 等,这些操作都是由 HandlerApater 来完成,开发者只需将注意力集中业务逻辑的处理上,DispatcherServlet 通过 HandlerAdapter 执行不同的 Handler。
- ModelAndView:装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。
- ViewResolver:视图解析器,DispatcheServlet 通过它将逻辑视图解析为物理视图,最终将渲染结果响应给客户端。
SpringMVC的主要组件
1 2 是核心
现在我们的项目都是前后端分离,后面的一些组件跟JSP有关,我们没怎么用了
Springmvc 如何做异常处理 ?
可以将异常抛给Spring框架,由Spring框架来处理;自定义实现spring的全局异常解析器HandlerExceptionResolver,在异常处理器中添视图页面即可。
Springmvc 的控制器是不是单例模式,如果是,有什么问题,怎么解决?
是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段。
Springmvc 和struts2的区别有哪些?
我没用过struts2,我只简单谈。
springmvc的入口是一个servlet即前端控制器(DispatchServlet),而struts2入口是一个filter过虑器(StrutsPrepareAndExecuteFilter)。
SpringMVC如何解决get/post中文乱码问题
GET方式:
更简便的方法,在服务器端配置URL编码格式:修改tomcat的配置文件server.xml:只需增加 URIEncoding=“UTF-8”
这一句,然后重启tomcat即可。
POST方式:
可以每次在request解析数据时设置编码格式:request.setCharacterEncoding(“utf-8”);
也可以用过滤器
MyBatis
mybatis是什么?如何用?
mybatis是一个优秀的持久层框架,他对jdbc操作数据库的过程进行了封装,使开发着只用关注sql本身,不用去关注例如注册驱动,加载链接,得到statement,处理结果集等复杂的过程。<br /> mybatis通过xml或者注解的方式,将要执行的各种sql语句配置起来,并通过Java对象和statement中的sql语句映射生成最终的sql语句,最后由mybatis框架执行sql语句,并将结果映射成Java对象返回。
mybatis解决的问题
1.使用数据库连接池管理链接,避免了频繁创建了、关闭链接,浪费资源,影响性能的问题。
2.用xml管理sql语句,让Java代码和sql语句分离,使得代码更易维护。
3.解决了sql语句参数不定的问题。xml中可以通过where条件决定sql语句的条件参数。mybatis将Java对象映射到sql语句,通过statement的parameterType定义输入参数的类型。
4.mybatis自动将结果集封装成Java对象, 通过statement的resultType定义输出的类型。避免了因sql变化,对结果集处理麻烦的问题。
mybatis和hibernate区别
SQL和ORM的争论,永远不会终止 表结构设计/面向对象思维
首先他们都是持久层框架。
- 开发速度:hibernate效率快,基本sql已经被封装好;sql适合有复杂查询的大项目
- 工作量:hibernate有良好的映射机制;Mybatis需要手动写sql以及ResultMap
- SQL优化:hibernate会查询所有字段,有性能消耗;Mybatis手动写sql,按需查询
- 对象管理:hibernate的ORM提供对象管理功能,更面向对象;Mybatis需要程序员自己对对象进行管理
- 缓存机制:都有二级缓存,但是hibernate在使用二级缓存读脏数据时系统会报错提示
简述Mybatis的插件运行原理,如何编写一个插件
Mybatis的插件实际上就是拦截器。
#{}和${}的区别
mybatis如何防止sql注入,为什么需要预编译
定义:
SQL 预编译指的是数据库驱动在发送 SQL 语句和参数给 DBMS 之前对 SQL 语句进行编译,这样 DBMS 执行 SQL 时,就不需要重新编译。
为什么需要预编译
JDBC 中使用对象 PreparedStatement 来抽象预编译语句,使用预编译。预编译阶段可以优化 SQL 的执行。预编译之后的 SQL 多数情况下可以直接执行,DBMS 不需要再次编译,越复杂的SQL,编译的复杂度将越大,预编译阶段可以合并多次操作为一个操作。同时预编译语句对象可以重复利用。把一个 SQL 预编译后产生的 PreparedStatement 对象缓存下来,下次对于同一个SQL,可以直接使用这个缓存的 PreparedState 对象。Mybatis默认情况下,将对所有的 SQL 进行预编译。
MyBatis工作原理 重点
mybatis通过配置文件创建sqlsessionFactory,sqlsessionFactory根据配置文件,配置文件来源于两个方面:一个是xml,一个是Java中的注解,获取sqlSession。SQLSession包含了执行sql语句的所有方法,可以通过SQLSession直接运行映射的sql语句,完成对数据的增删改查和事物的提交工作,用完之后关闭SQLSession。
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 对结果集的解析过程。
MyBatis的缓存
mybatis的查询缓存分为一级缓存和二级缓存,一级缓存是SqlSession级别的缓存,二级缓存时mapper级别的缓存,二级缓存是多个SqlSession共享的。mybatis通过缓存机制减轻数据压力,提高数据库性能。
一级缓存:
mybatis的一级缓存是SQLSession级别的缓存,在操作数据库时需要构造SqlSession对象,在对象中有一个HashMap用于存储缓存数据,不同的SqlSession之间缓存数据区域(HashMap)是互相不影响的。
一级缓存的作用域是SqlSession范围的,当在同一个SqlSession中执行两次相同的sql语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存)中,第二次查询时会从缓存中获取数据,不再去底层进行数据库查询,从而提高了查询效率。需要注意的是:如果SqlSession执行了DML操作(insert、update、delete),并执行commit()操作,mybatis则会清空SqlSession中的一级缓存,这样做的目的是为了保证缓存数据中存储的是最新的信息,避免出现脏读现象。
当一个SqlSession结束后该SqlSession中的一级缓存也就不存在了,Mybatis默认开启一级缓存,不需要进行任何配置。
二级缓存:
二级缓存是mapper级别的缓存,使用二级缓存时,多个SqlSession使用同一个Mapper的sql语句去操作数据库,得到的数据会存在二级缓存区域,相比一级缓存SqlSession,二级缓存的范围更大,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的SqlSession两次执行相同的namespace下的sql语句,且向sql中传递的参数也相同,即最终执行相同的sql语句,则第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。
Mybatis默认没有开启二级缓存,需要在setting全局参数中配置开启二级缓存。
Mybatis是如何进行分页的?分页插件的原理是什么?
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
举例:select from student,拦截sql后重写为:select t. from (select * from student)t limit 0,10
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的功能。
Mapper/DAO接口问题及原理
Dao接口,就是人们常说的Mapper接口。
接口的全限名,就是映射文件中的namespace的值
接口的方法名,就是映射文件中MappedStatement的id值
接口方法内的参数,就是传递给sql的参数。
mapper接口是没有实现类的,当调用一个方法时,接口的全类名定位一个配置文件,接口的方法名定位这个配置文件中的一个mapperStatment,所以说mapper的方法名是不能重载的,因为mapperStatment的保存和寻找策略。
mapper接口的工作原理是,mybatis会使用jdk动态代理方式为mapper接口创建proxy对象,代理对象会拦截接口中的方法,转而执行mapperStatment所代表的sql语句,然后将执行的结果封装返回。
其他小知识点
pojo和bean区别
- Bean是POJO的一种,反之不成立。
- 所有的Bean都应该实现Serializable接口。而POJO没有这项要求。