查看原文
其他

搞不定MyBatis面试,速看全面MyBatis面试题及答案整理总结

素文宅博客 Java精选 2022-08-09

MyBatis是一款的持久层框架,支持定制化SQL、存储过程以及高级映射,它避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。目前MyBatis在互联网行业应用广泛,几乎所有后端技术面试官都会问一些关于Mybatis方面的面试题。

本篇通俗易懂的为大家整理总结了近年来针对MyBatis开源框架的相关面试题并附有答案,希望对大家在以后的面试中有所帮助并且能够顺利的拿到OFFER。欢迎关注“Java精选”微信公众号,持续更新Redis、MyBatis、MySQL等框架面试题及答案。

  什么是MyBatis?

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

MyBatis前身是ibatis,但是在配置sql语法上有明显的区别且Spring目前的版本封装了MyBatis,至于mybatis-spring.jar文件也是mybatis团队负责开发的jar包用于与Spring整合。

  MyBatis框架优缺点,适用于什么场合?

1、优点
1)与JDBC相比,减少了编写代码量。
2)MyBatis是最简单的持久化框架之一,易于上手掌握,提供数据库查询的自动对象绑定功能,对于要求不高的对象模型项目来说相当完美。
3)MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,在xml中编写SQL语句使得从程序代码中彻底分离,降低耦合度,便于统一管理和优化,并可重复使用。
4)提供XML标签,支持编写动态SQL语句。
5)提供对象映射标签,支持对象与数据库的ORM字段关系映射。
2、缺点
1)多表关联时由于字段过多导致编写SQL语句的工作量大。
2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
3)由于xml中ID标签必须唯一,导致DAO中方法不支持重载方法。
4)对象关系映射标签和字段映射标签仅仅是对映射关系的描述,具体实现依赖于SQL语句。
5)Mybatis日志除基本记录功能外,其它功能相对简单。
6)编写动态SQL语句,在逻辑复杂时不方便调试。
3、适用场合
1)MyBatis专注于SQL语句本身,是一个足够灵活的DAO层解决方案;

2)对于性能方面要求高或需求变化较多的项目,MyBatis开源框架是一个不错的选择。

  MyBatis与Hibernate有哪些不同?

1、相同点
1)两者都是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory生成Session,最后由Session来开启执行事务和SQL语句。
2)其中SessionFactoryBuider,SessionFactory,Session的生命周期类似。
3)Hibernate和MyBatis都支持JDBC和JTA事务处理。
2、不同点
1)Hibernate是全自动,而MyBatis是半自动。
2)Hibernate数据库移植性远大于MyBatis。
3)Hibernate拥有完整的日志系统,而Mybatis日志管理比较简单。
4)Mybatis在SQL优化方面比Hibernate方便很多。

5)Hibernate在缓存机制上比Mybatis更好一些。

  在MyBatis框架中#{}和${}的区别是什么?

1、#{}表示一个占位符号
通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止SQL注入。 
#{}可以接收简单类型值或pojo属性值。如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
2、${}表示拼接SQL串

通过${}可以将parameterType传入的内容拼接在SQL中且不进行jdbc类型转换,${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

  在实体类中的属性名和表中的字段名不同如何解决?

1、使用SQL语句别名
sql语句如下:
select id,user_name username,user_role userrole from userinfo;
将数据库中的user_name映射为实体类中的username属性。
2、xml文件全局配置驼峰命名规则
在数据库中的下划线映射为驼峰命名规则,参考配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
</configuration>

注:数据库中表字段属性值的下划线必须经凑如“user_name”,避免出现空格等特殊字符。

3、使用resultMap自定义高级映射

在Mapper映射文件中使用resultMap自定义高级映射,参考配置文件如下:
<select id="selectUsers" resultMap="userMap">
select id,user_name,user_role from userinfo;
</select >
<resultMap type="com.yoodb.entities.UserInfo" id="userMap">
<!--映射主键-->
<id column="id" property="id"/>
<!--映射其他property对应实体类中的属性名-->
<result column="user_name" property="username"/>
</resultMap>
  模糊查询like语句一般怎么写?
1、'%${username}%'
<select id="selectUsers" resultMap="userMap" parameterType="com.yoodb.entities.UserInfo">
select id,user_name,user_role from userinfo where user_name like '%${username}%'
</select >
注:由于$是参数直接注入,大括号里面不能注明jdbcType类型,不然会报错。
2、"%"#{username,jdbcType=VARCHAR}"%"
<select id="selectUsers" resultMap="userMap" parameterType="com.yoodb.entities.UserInfo">
select id,user_name,user_role
from userinfo where user_name
like "%"#{username,jdbcType=VARCHAR}"%"
</select >
注:因为#{...}解析SQL语句时会把变量外侧自动加单引号,所有%号需要使用双引号,不能使用单引号,不然无法查询出结果。
3、CONCAT('%',#{username},'%')
<select id="selectUsers" resultMap="userMap" parameterType="com.yoodb.entities.UserInfo">
select id,user_name,user_role from
userinfo where user_name like
CONCAT('%',#{username,jdbcType=VARCHAR},'%')
</select >

注:使用CONCAT函数连接参数,推荐使用此方法。

  MyBatis是如何进行分页的?分页插件的原理是什么?
MyBatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。可以在SQL语句内直接编写带有物理分页的参数来完成物理分页功能,也可以使用pageHelper分页插件来完成物理分页。
1)物理分页依赖的是某一物理实体,这个物理实体就是数据库,比如MySQL数据库提供了limit关键字,程序员只需要编写带有limit关键字的SQL语句,数据库返回的就是分页结果。
2)逻辑分页即内存分页依赖的是程序员编写的代码。数据库返回的不是分页结果,而是全部数据,然后再由程序员通过代码获取分页数据,常用的操作是一次性从数据库中查询出全部数据并存储到List集合中,因为List集合有序,再根据索引获取指定范围的数据。

分页插件的基本原理是使用MyBatis提供的插件接口实现自定义插件,在插件的拦截方法内拦截待执行的SQL语句,然后重写SQL语句,根据dialect方言添加对应的物理分页语句和物理分页参数。

  如何获取自动生成的(主)键值?

insert方法总是返回一个int值 ,这个值代表的是插入行数。如果采用自增长策略,自动生成的键值在 insert 方法执行完后可以被设置到传入的参数对象中。
1、MYSQL
<insert id=”insertusername” usegeneratedkeys=”true” keyproperty=”id”>
insert into user_name (username) values (#{username})
</insert>
2、Oracle
<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
select xxx_SEQ.nextval from dual
</selectKey>

  在mapper中如何传递多个参数?

1、顺序传参法
DAO层的方法
public selectUser(String username,String userrole); <select id="selectUser" resultMap="userMap">
select * from userinfo where user_name = #{0} and user_role=#{1};
</select>
注:对应的xml文件中#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数往后追加即可。
2、采用@param注解
public interface Usermapper {
user selectUser(@param(“username”) string username,@param("userrole") string userrole);
}
<select id=”selectuser” resultMap="userMap">
select id, user_name, user_role
from userinfo where user_name = #{username} and user_role = #{userrole}
</select>
注:#{}里面的名称对应的是注解@Param括号里面修饰的名称,这种方法在参数不多的情况还是比较直观的,推荐使用。
3、Java Bean传参法
<select id=”selectuser” resultMap="userMap" parameterType="com.yoodb.entities.UserInfo">
select id, user_name, user_role
from userinfo where
user_name = #{username} and user_role = #{userrole}
</select>
注:#{}里面的名称对应的是 UserInfo类里面的成员属性,这种方法需要建一个实体类,扩展不方便需要增加属性,视情况使用。
4、Map传参法
<select id=”selectuser” resultMap="userMap" parameterType="java.util.Map">
select id, user_name, user_role
from userinfo where
user_name = #{username} and user_role = #{userrole}
</select>

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

  MyBatis动态sql有什么用?有哪些动态sql?简述一下执行原理?

MyBatis动态sql可以在xml映射文件内以标签的形式编写动态sql语句。
MyBatis提供了9种动态sql标签分别是trim、where、set、foreach、if、choose、when、otherwise、bind。

执行原理是根据表达式的值来完成逻辑判断并动态拼接sql的功能。

  为什么MyBatis是半自动ORM映射工具?它与全自动有什么区别?

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

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

MyBatis仅支持association关联对象和collection关联集合对象的延迟加载。

association指一对一查询,而collection指一对多查询。在Mybatis配置文件中可以配置是否启用延迟加载,通过lazyLoadingEnabled参数,设置true或者false值。

MyBatis的实现原理是使用CGLIB创建目标对象的代理对象,当调用目标方法时进入拦截器方法,比如调用a.getB().getName()方法,拦截器invoke()方法会发现a.getB()是空值,那么就会单独发送之前以保存的查询关联B对象的sql语句,把B查询之后调用a.setB(b)方法,于是a的对象b属性就有了值,最后完成a.getB().getName()方法的调用。

  简述MyBatis的插件运行原理及如何编写一个插件?

1、MyBatis插件运行原理
MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能。
MyBatis允许在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis允许使用插件来拦截的方法调用包括:
//拦截执行器的方法
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed);
//拦截参数的处理
ParameterHandler (getParameterObject, setParameters);
//拦截结果集的处理
ResultSetHandler (handleResultSets, handleOutputParameters);
//拦截Sql语法构建的处理
StatementHandler (prepare, parameterize, batch, update, query);
MyBatis采用责任链模式,通过动态代理组织多个拦截器(插件),这些拦截器可以改变MyBatis的默认行为(诸如SQL重写之类的),由于插件会深入到MyBatis的核心,因此在编写自定义插件时了解一下其原理以便于写出安全高效的插件。
2、编写插件简易步骤
1)编写Intercepror接口的实现类;
2)设置插件的签名,告诉mybatis拦截哪个对象的哪个方法;
3)将插件注册到全局配置文件中。
  MyBatis都有哪些Executor执行器?它们之间的区别是什么?
MyBatis有三种基本的Executor执行器,分别是SimpleExecutor、ReuseExecutor、BatchExecutor。
SimpleExecutor
每执行一次update或select,就开启一个新的Statement对象,用完马上关闭Statement对象。
ReuseExecutor
执行update或select,以sql作为key查找Statement对象,存在即用,不存在创建,使用完后不关闭Statement对象,而是放置于Map内供下一次使用。换言之,就是重复使用Statement对象。
BatchExecutor
执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理,它的处理方式与JDBC批处理相同。

MyBatis中Executor的这些特点,都严格限制在SqlSession生命周期范围内。欢迎关注“Java精选”微信公众号,回复关键词可免费获取Java相关视频资料和项目源码。

  什么情况下用注解绑定,什么情况下用xml绑定?

1、SQL语句比较简单时可以使用注解绑定;

2、SQL语句比较复杂时可以使用xml绑定,一般情况下xml绑定使用比较普遍。

  MyBatis实现一对一有几种方式?它们之间的区别有哪些?

MyBatis实现一对一有联合查询和嵌套查询。
联合查询是几个表联合查询但只查询一次,通过在resultMap里面配置association节点配置一对一的类实现;

嵌套查询是先查一个表,根据这个表中的结果外键id,通过association配置再去另外一个表中查询数据,但这个表的查询要通过select属性配置。

  MyBatis实现一对多有几种方式,它们之间的区别有哪些?

MyBatis实现一对多有联合查询和嵌套查询。
联合查询是几个表联合查询,只查询一次,通过在resultMap里面的collection节点配置一对多的类就可以完成;

嵌套查询是先查一个表,根据这个表里面的结果的外键id,通过collection配置再去另外一个表中查询数据,去再另外一个表里面查询数据,但这个表的查询通过select节点配置。

  使用MyBatis中mapper接口调用时有哪些要求?

1、Mapper接口方法名和mapper.xml文件中定义的每个sql语句id相同;
2、Mapper接口方法的输入参数类型和mapper.xml文件中定义的每个sql语句parameterType的类型相同;
3、Mapper接口方法的输出参数类型和mapper.xml文件中定义的每个sql语句resultType的类型相同;

4、Mapper.xml文件中的namespace即是mapper接口的类路径。

  MyBatis中不同的xml映射文件id是否可以重复?

MyBatis中不同的xml映射文件如果配置了namespace,那么id就可以重复;如果没有配置namespace,那么id不能重复。

xml映射文件配置了namespace,那么id是作为Map<String, MappedStatement>的key使用的,如果没有namespace,那么id重复会导致数据相互覆盖。

推荐阅读

搞不定Redis面试,速看全面Redis面试题及答案整理总结

超级全面的总结MySQL数据库优化面试题分析

Java面试技巧—面试者简历如何通过初步筛选

IntelliJ IDEA使用技巧——IDEA常用快捷键01期

IntelliJ IDEA使用技巧——IDEA增加jar包02期

IntelliJ IDEA使用技巧——IDEA工具Debug模式断点调试详解03期

IntelliJ IDEA使用技巧—IDEA设置默认Maven版本04期

IntelliJ IDEA使用技巧—使用EasyCode插件一键生成代码05期

IntelliJ IDEA使用技巧—在IDEA中Project和Module的概念、区别与关系06期

IntelliJ IDEA使用技巧—在IDEA使用中常用设置及性能优化图解07期
更多推荐↓↓↓
 

关注下方微信公众号“Java精选”(w_z90110),回复关键词领取资料:如Mysql,Hadoop,Dubbo,Spring Boot等,免费领取视频教程、资料文档和项目源码。
Java精选专注程序员推送一些Java开发知识,包括基础知识、各大流行框架、大数据技术、数据库、算法与数据结构、面试专题、面试技巧经验、职业规划以及优质开源项目等。其中一部分由小编总结整理,另一部分来源于网络上优质资源,希望对大家的学习和工作有所帮助。
我就知道你“在看”!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存