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

 2022-08-22
原文地址:https://blog.51cto.com/u_15191078/5280132

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

202208222301147691.png

本篇通俗易懂的为大家整理总结了近年来针对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);