写点什么

这份 P7 大牛分享的 MyBatis 面试题总结,太好用了!美团面试过了

发布于: 2021 年 04 月 29 日
这份P7大牛分享的MyBatis面试题总结,太好用了!美团面试过了

今日分享开始啦,请大家多多指教~

MyBatis 面试题总结

前言:

今天给大家分享的是面试中会遇到的几点问题,希望这次分享可以让大家面试更加顺利!

1.#{}与 ${}的区别?

2.Xml 映射文件中,除了常见的 select/Inserct/update/delete 标签之外,还有那些标签?

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

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

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

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

7.Mybatis 能执行一对一、一对多的关联查询吗?都有那些实现方式,以及他们之间的区别?

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

9.Mybatis 的 XML 映射文件中,不同的 XML 映射文件,id 是否可以重复?

10.Mybatis 都有哪些 Executor 执行器?他们之间的区别是什么?

11.Mybatis 中如何制定使用哪一种 Executor 执行器?

12.Mybatis 是否可以映射 Enum 枚举类?

13.Mybatis 映射文件中,如果 A 标签通过 include 引用了 B 标签的内容,请问 B 标签的内容是否定义在 A 标签之后,还是必须定义为 A 之前?

14.Mybatis 与 Spring dataJpa 的区别?

话不多说,正文开始啦~

1.#{}与 ${}的区别

#{}:是 sql 的参数占位符,Mybatis 会将 sql 中的 #{}替换为?,按序给 sql 的?占位符设置参数值。

这个是根据参数变化不是动态 sql(是有 if 语句之类的 sql)

${}:是在数据库配置文件中的变量占位符,属于静态文本替换,比如 ${Driver}会被静态替换为 com.mysql.jdbc.Driver。

2.Xml 映射文件中,除了常见的 select/Inserct/update/delete 标签之外,还有那些标签?

还有<resultMap>,<parameterMap>,<sql>,<include>,<selectKey>,加上动态 sql 的 9 个标签等。<include>是可以引入其他 sql 片段,<selectKey>为不支持自增的主键生成策略标签。

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

Dao 接口,就是人们常说的 Mapper 接口,接口的全限名,就是映射文件中的 namespace 的值,接口的方法名,就是映射文件中 MappedStatement 的 id 值,接口方法内的参数,就是传递给 sql 的参数。Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MappedStatement。

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

Dao 接口的工作原理是 JDK 动态代理,MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 独享,代理对象 proxy 会拦截接口方法,转而执行 MappedStatement 所代表的 sql,然后将 sql 执行结果返回。

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

1.Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分离,而非物理分页;

RowBounds 分页(不使用 SQL),不再使用 SQL 实现分页

接口

List <User> getUserByRowBound();
复制代码

mapper.xml

测试

2.直接在 sql 内直接书写 limit 进行分页;

使用 Limit 分页

Select    *  from   user  limit  2;#[0,n]
复制代码

【0,2】出来的时候第一个和第二个。所以 0 代表的第一个。

3.使用分页插件来完成物理分页。

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


Mybatis 动态 sql 可以让我们在 xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能,Mybatis 提供了 9 种动态 sql 标签

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

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

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

第二种是使用 sql 列的别名功能,将列名书写为对象属性名。

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

7.Mybatis 能执行一对一、一对多的关联查询吗?都有那些实现方式,以及他们之间的区别?

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

关联对象查询,有两种方式:

一种是单独发送一个 sql 去查询关联对象 resultMap,赋给主对象,然后返回主对象;

按照查询嵌套处理(子查询)

另一种是使用嵌套查询,嵌套查询的含义为使用 join 查询,一部分列是 A 对象的属性值,另外一部分是关联对象 B 的属性值,好处是只发一个 sql 查询,就可以把主对象和其关联对象查出来。

按照查询嵌套处理(联表查询)

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

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

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

9.Mybatis 的 XML 映射文件中,不同的 XML 映射文件,id 是否可以重复?

不同的 XML 映射文件,如果配置了 Namespace,那么 Id 可以重复;如果没有配置 namespace,那么 Id 不能重复;毕竟 Namespace 不是必须加的,只是最佳实践而已。

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

10.Mybatis 都有哪些 Executor 执行器?他们之间的区别是什么?

有三种:SimpleExecutor、ReuseExector、BatchExector。

SimpleExecutor:每执行一次 update 或 select,就会开启 Statement 对象,用完立刻关闭 Statement 对象。

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

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

11.Mybatis 中如何制定使用哪一种 Executor 执行器?

在 Mybatis 配置文件中,可以指定默认的 ExecutorType 执行器类型,也可以手动给 DefalutSqlSessionFactory 的创建 SqlSession 的方法传递 ExecutorType 类型参数。

12.Mybatis 是否可以映射 Enum 枚举类?

Mybatis 可以映射枚举类,不但可以映射枚举类,Mybatis 可以映射任何对象到表的一列上。映射方法为自定义一个 TypeHandler,实现 TypeHandler 的 setParameter()和 getResult()接口方法。TypeHandler 有两个作用,一是完成从 javaType 至 jdbcType 的转换,二是完成 jdbcType 至 javaType 的转换,体现为 setParameter()和 getResult()两个方法,分别代表设置 sql 问好占位符参数和获取列查询结果。

13.Mybatis 映射文件中,如果 A 标签通过 include 引用了 B 标签的内容,请问 B 标签的内容是否定义在 A 标签之后,还是必须定义为 A 之前?

虽然 Mybatis 解析 Xml 映射文件是按顺序接续的,但是,被引用的 B 标签依然可以定义在任何地方,Mybatis 都可以正确识别。

原理是,当我 A 包含了 B 的时候,Mybatis 解析到 A 的时候,发现 B 还没有,会将 A 设置为未解析状态,然后继续解析下面的标签,待所有标签都解析完全后,再去解析一次未解析的标签。

14.Mybatis 与 Spring dataJpa 的区别

首先,SprigData JPA 可以理解为对 Jpa 规范再次封装抽象,底层还是使用 hibernate 框架的 JPA 技术实现。

JPA 默认使用 Hibernate 技术实现,所以,一般使用 Springdata JPA 也就是 hibernate。

Hibernate 是一个开放源代码的对象关系映射框架,他对 JDBC 进行非常轻量级的对象封装。它将 POJO 与数据库表建立映射关系,是一个全自动的 orm 框架,hibernate 可以自动生成 SQL 语句,使得 Java 成员可以随心所欲的使用对象编程思维来操纵数据库。

Mybatis 是一款优秀的持久层框架,它支持定制化 SQL、储存过程以及高级映射。Mybatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。Mybatis 可以使用简单的 XML 或者注解来配置和映射原生信息,将接口和 Java 的 entity 对象映射成数据库中的记录。

所以,我们说 jpa 和 mybatis 的区别也就说 hibernate 和 mybatis 的区别。

Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件),用 Hibernate 开发可以节省很多代码,提高效率。但是学习门槛高,要精通门槛更高,而且还要满足设计 O/R(Object/Relation)映射,在性能和对象模型之间如何权衡,我实习中看 powerdesigner 中的数据模型,的确挺多表。多对多的表中,中间又有一个关联表,因此我这边写代码 pojo 的时候也会多一个类。

总的来说,Mybatis 可以进行更细致的 SQL 优化,查询必要的字段,但是需要维护 SQL 和查询结果集的映射。数据库的移植性较差,针对不同的数据库编写不同的 SQL。

Hibernate 对数据库提供了较为完整的封装,封装了基本的 DAO 层操作,有较好的数据库移植性,但是学习周期长,开发难度大于 Mybatis。


小结:

Mybatis 学习门槛低,简单易学,程序员直接编写 sql,可严格控制 sql 执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。


今日份分享已结束,请大家多多包涵和指点!

用户头像

还未添加个人签名 2021.04.20 加入

Java工具与相关资料获取等WX: pfx950924(备注来源)

评论

发布
暂无评论
这份P7大牛分享的MyBatis面试题总结,太好用了!美团面试过了