MyBatis面试题汇总

1、 MyBatis简述

a) 基本概念: MyBatis是一款优秀的半自动化ORM框架(DAO层框架),前身是IBatis,支持动态sql、存储过程及高级映射。半自动化是指:MyBatis在查询关联对象或关联集合对象时,主要手动编写sql来完成,所以称之为半自动化。ORM:通过业务实体对象和关系数据库中的字段做映射,将java程序中的对象自动持久化到数据库中,是一种数据持久化方案。
b) 作用: 主要通过封装JDBC的方法实现简化数据库与java之间的连接,几乎避免了所有JDBC代码和手动设置参数以及获取结果集,相比JDBC减少了50%的代码量。
c) 优点: 代码量减少;最简单的持久化框架,小巧并简单易学;sql代码彻底从程序中分离,可重用;提供xml标签,支持编写动态sql;提供映射标签,支持对象与数据库的ORM字段映射。
d) 缺点: sql语句编写工作量大,对开发人员有一定要求;数据库移植性差,因为不同的数据库编写的sql语句有差异,更换不同的数据库时sql语句也要做相应更改。

2、 什么是数据持久化?ORM原理?

a) 数据持久化:狭义的理解:“持久化”仅仅指把域对象永久保存到数据库中;广义的理解,“持久化”包括和数据库相关的各种操作。
i. ● 保存:把域对象永久保存到数据库。
ii. ● 更新:更新数据库中域对象的状态。
iii. ● 删除:从数据库中删除一个域对象。
iv. ● 加载:根据特定的OID,把一个域对象从数据库加载到内存。
v. ● 查询:根据特定的查询条件,把符合查询条件的一个或多个域对象从数据库加载内在存中。2.为什么要持久化?持久化技术封装了数据访问细节,为大部分业务逻辑提供面向对象的API。
vi. ● 通过持久化技术可以减少访问数据库数据次数,增加应用程序执行速度;● 代码重用性高,能够完成大部分数据库操作;
vii. ● 松散耦合,使持久化不依赖于底层数据库和上层业务逻辑实现,更换数据库时只需修改配置文件而不用修改代码。(OID[object identifier ]:对象标识,为了区分对象为每个对象分配的唯一一个编码)(域对象:可以在不同的Servlet之间传递数据的对象) (详:ORM原理和数据持久化

b) ORM原理(对象/关系映射,数据持久化技术)
编写程序的时候,以面向对象的方式处理数据
保存数据的时候,以关系型数据库的方式存储(详:ORM原理

3、 MyBatis的核心接口和类及生命周期

a) SqlSessionFactoryBuilder(构造器)

i. 作用:根据配置信息或代码来生成SqlSessionFactory
ii. 实现原理:负责构建SqlSessionFactory,该类提供了多个build()方法重载,而真正重载build()方法只有三种,分别是InputStream(字节流)、Reader(字符流)、Configuration(类),字节流和字符流都是通过xml配置文件的形式创建SqlSessionFactory,而Configuration采用的是java代码方式创建,常用的是读取配置文件的形式
iii. 生命周期:用过即丢,其生命周期只存在于方法体内

b) SqlSessionFactory(工厂接口)

i. 作用:是每个MyBatis应用的核心,可创建多个SqlSession实例,代码如下
SqlSession sqlSession=sqlSessionFactory.openSession(boolean autoCommit);
ii. 作用域:Application全局作用域
iii. 生命周期:与应用的生命周期相同
iv. 特点:单例(设计模式):存在于整个应用运行时,并且只存在一个对象实例

c) SqlSession(sql会话)

i. 作用:(1)获取映射器,让映射器通过命名空间和方法名称找到对应的sql,发送给数据库执行后返回结果; (2)通过update、insert、select、delete等方法,带上SQL的id来操作在XML中配置好的SQL,从而完成工作,与此同时它也支持事务,通过commit、rollback方法提交或者回滚事务。
ii. 特点:一个SqlSession对应一次数据库会话,会话结束必须关闭
可以执行多次sql语句,但是一旦关闭就需要重新创建SqlSession
线程级,不可共享会话(非线程安全)
iii. 作用域:相当request(一次请求)或方法体内的作用域

4、 SqlSession两种使用方式

a) 通过SqlSession实例直接运行映射xml文件的sql语句

List<User> userList=sqlSession.selectList(“cn.smbms.dao.UserMapper.getAllUserList”);

b) 基于Mapper接口方式操作数据(常用)

  List<User> userList=sqlSession.getMapper(UserMapper.class).getAlluserList();

注:

  • 如果使用第一种方式:在xml文件中的namespace属性值和id要与selectList()方法中的参数值完全匹配;namespcae属性值名可以随便起。
  • 如果使用第二种方式:则xml中的namespace属性值必须为mapper接口的完全 限定名,将xml文件与mapper接口相关联。
  • 不管使用哪种方式:接口中的方法名与xml文件中配置的id名必须完全一致

5、 #{}${}的区别

a) #{}表示一个占位符,可以实现preparedStatement向占位符中设置值,可以有效防止sql注入,#{}可以接受基本数据类型值或pojo属性值,如果parametreType传输的是基本数据类型值,那么{}中可以放value或其他名称。

b) ${}表示拼接sql串,通过${}可以将parameterType传入的内容不进行jdbc类型转换,可以接受基本数据类型值或pojo属性值,如果parametreType传输的是基本数据类型值,那么{}中只能放alue,其他情况必须与pojo属性名相同

6、 系统核心配置文件结构

a) configuration配置 (根节点)
properties 可以在配置java属性配置文件中
settings 修改MyBatis在运行时的行为方式(设置log4j)
typeAliases 为java类型命名一个别名
typeHanlers 类型处理器
objectFactory 对象工厂
plugins 插件
environments 配置运行环境(可配置多个运行环境environment:例如数据源、事务等)
environment 环境变量
transactionManager 事务管理器
dataSource 数据源
mappers 映射器(将mapper文件加入到配置文件中)

7、 MyBatis执行原理

mybatis运行时要先通过resources把核心配置文件也就是mybatis.xml文件加载进来,然后通过xmlConfigBulider来解析,解析完成后把结果放入configuration中,并把它作为参数传入到build()方法中,并返回一个defaultSQLSessionFactory。我们再调用openSession()方法,来获取SqlSession,在构建SqlSession的同时还需要transaction和executor用于后续执行操作。 (详:MyBatis运行原理

8、 resultType和resultMap的区别与关联

a) 区别: resultType直接表示返回类型,包括基础数据类型和复杂数据类型。resultMap则是对外部resultMap定义的引用,对应外部resultMap的id,表示返回结果映射到哪一个resultMap上。应用场景:数据库字段信息和对象属性不一致或需要做复杂的联合查询
b) 关联: 在使用MyBatis进行查询映射时,实际上查询出的每个字段信息都放在一个对应的map里面,key对象字段名,value对应相应的值,当select元素提供的返回类型属性为resultType时,MyBatis会将map中的键值对取出赋给resultType所指定的对象的属性(即调用对象属性的setter方法)。因此,当使用resultType,直接在后台就能接收到相应的对象属性值。由此可看出,其实MyBatis的每个查询映射的返回值类型都是resultMap,只是当提供的返回值类型是resultType时,MyBatis会自动把对应的值赋给指定对象的属性,而当返回值类型为resultMap时,因为map不能很好的表示领域模型,所以需要手动转化为对应的实体对象。( 领域模型:业务对象模型[对象])。
c) 注:
i. 在MayBatis的select元素中,resultType与resultMap本质是一样的,都是Map数据结构,但resultType和resultMap属性绝对不能同时存在,只可二选一
ii. resultMap的自动映射级别:使用resultMap自动映射的前提是属性名和自动名必须一致,在默认映射级别(PARTIAL)情况下,如果没有做匹配也可以在后台获取到未匹配过的属性值;若不一致且在resultMap中没有做映射,则无法获取到数据

9、 JavaBean中字段与数据库列无法映射的原因及解决方法

a) 字段与数据库列名不一致
解决方案

  • 为查询出的字段起别名,保证名称与类中属性名相同(缺点:在查询字段过多的情况下会降低代码可读性且导致重复代码增多)
  • 因为Mybatis映射的原理就是通过返回的数据库字段名找实体类的setXxx方法进行对应注入,故可以采用让实体类set方法名对应数据库字段名
  • (推荐)利用XxxMapper.xml的sql标签(同解决方案一原理相同,将方案一提取封装,简化操作)
  • (推荐)使用resultMap手动映射一个数据结果的封装规则

b) 没有相对应的getter/setter方法

  • 为属性添加相应的getter、setter方法

10、 resultMap的自动映射级别

a) NONE:禁止自动匹配
b) PARTIAL(默认):自动匹配所有属性,有内部嵌套的除外
c) FULL:匹配所有

11、 最佳实践中,通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao 接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?

  • DAO接口,就是人们常说的Mapper接口,接口的全限名就是映射文件中namespace的值,接口的方法名,就是映射文件中MapperdStatement的id值,接口方法内的参数就是传递给sql的参数。Mapper接口是没有实现类类的,当调用接口方法时,接口全限名+方法名拼接的字符串为key,可唯一定位一个MapperdStatement。
  • DAO接口里的方法是不能重载的,因为是全限名+方法 名的保存和寻找策略,
  • DAO接口的原理是JDK动态代理,MyBatis运行时会使用JDK动态代理为DAO接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MapperdStatement所代表的sql,然后执行sql返回结果

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

  • 还有很多其他的标签,、、、、,加上动态sql的9个标签,trim 、where 、 set 、foreach、if、choose、when、otherwise、bind等,其中为sql片段标签,通过标签引入sql片段,为不支持自增的主键生成策略标签。

13、 Mybatis是如何进行分页的?分页插件的原理是什么?

  • 答:Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
  • 分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
  • 举例:select * from student,拦截sql后重写为:
    select t.* from (select * from student)t limit 0,10

14、 简述Mybatis的插件运行原理,以及如何编写一个插件。

  • Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。
  • 实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件

15、 Mybatis动态sql是做什么的?都有哪些动态sql?能简述一下动态sql的执行原理不?

  • Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能,Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。

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

  • 第一种是使用标签,逐一定义列名和对象属性名之间的映射关系。第二种是使用sql列的别名功能,将列别名书写为对象属性名,比如T_NAME AS NAME,对象属性名一般是name,小写,但是列名不区分大小写,Mybatis会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成T_NAME AS NaMe,Mybatis一样可以正常工作。有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

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

  • Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

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

  • 不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;毕竟namespace不是必须的,只是最佳实践而已。原因就是namespace+id是作为Map<String, MappedStatement>的key使用的,如果没有namespace,就剩下id,那么,id重复会导致数据互相覆盖。有了namespace,自然id就可以重复,namespace不同,namespace+id自然也就不同。

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

  • Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。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生命周期范围内。

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

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

21、 为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?

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

22、 JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?

1、 JDBC:数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
MyBatis:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。

2、 JDBC:Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
MyBatis:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。

3、 JDBC:向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
MyBatis: Mybatis自动将java对象映射至sql语句。

4、 JDBC:对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
MyBatis:Mybatis自动将sql执行结果映射至java对象。

23、 Mybatis中设计模式

  • Builder模式,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;
  • 工厂模式,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;
  • 单例模式,例如ErrorContext和LogFactory;
  • 代理模式,Mybatis实现的核心,比如MapperProxy、ConnectionLogger,用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;
  • 组合模式,例如SqlNode和各个子类ChooseSqlNode等;
  • 模板方法模式,例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;
  • 适配器模式,例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;
  • 装饰者模式,例如Cache包中的cache.decorators子包中等各个装饰者的实现;
  • 迭代器模式,例如迭代器模式PropertyTokenizer
    MyBatis设计模式
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值