MyBatis经典面试题

134 阅读5分钟

欢迎关注WX公众号:“程序猿补课班”,分享Java相关技术知识,学习经验,面试经验等。小伙伴快来补课吧!

正文开始

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

#是占位符,会对SQL进行预编译,相当于?; 

$是做sql拼接,有SQL注入的隐患 

两者都支持@param注解,指定参数名称,获取参数值. 

推荐这种方式一般做参数传递,都会使用#{}

如果不是做预编译,而是做拼接sql,会使用${}, 例如表名称的变化,

2.Mapper 接口如何传递多个参数?

方式一、接口中传多个参数,在 xml 中使用 #{param0}、#{param1}…

方式二、使用 @param 注解指定名称,在 xml 中使用 #{名称}

方式三、多个参数封装到 Java bean 中

方式四、多个参数指定 key,put 到 Map 中

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

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

第二种是使用 sql 列的别名功能,将列别名书写为对象属性名,比如 T_NAME AS NAME,对象属性名一般是 name,小写,但是列名不区分大小写,Mybatis 会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成T_NAME AS NaMe,Mybatis 一样可以正常工作。

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

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

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

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

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

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

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

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

a、Mybatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能。

b、Mybatis提供了9种动态sql标签:trim|where|set|foreach|if|choose|when|otherwise|bind。

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

7.使用 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 接口的类路径。

8.Mybatis 一级缓存和二级缓存了解吗?

一级缓存

Mybatis的一级缓存是指SQLSession,一级缓存的作用域是SQlSession, Mabits默认开启一级缓存。 在同一个SqlSession中,执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取。 

当执行SQL时候两次查询中间发生了增删改的操作,则SQLSession的缓存会被清空。 每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。

二级缓存

二级缓存是mapper级别的,Mybatis默认是没有开启二级缓存的。

第一次调用mapper下的SQL去查询用户的信息,查询到的信息会存放该mapper对应的二级缓存区域。 第二次调用namespace下的mapper映射文件中,相同的sql去查询用户信息,会去对应的二级缓存内取结果。

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

不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;

如果没有配置 namespace,那么 id 不能重复;原因就是 namespace+id 是作为 Map<String, MapperStatement>的 key使用的,如果没有 namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。

10.mybatis如何获取生成的主键

自增主键

第一种方式是使用useGeneratedKeys + keyProperty组合的方式,其中userGeneratedKeys代表是告诉mybatis要使用自增生成的主键,keyProperty是告诉mybatis主键字段是哪个,如下:

<insert id="insert" parameterType="Person" userGeneratedKeys="true" keyProperty="id">    
INSERT INTO person(name, pswd)    VALUE (#{name}, #{pswd})  
</insert>

对于不支持自动生成主键的数据库Oracle、DB2等,可以用元素selectKey 回写当前插入数据主键值到输入类中(同时生成一个自定义的随机主键),注意这里order="BEFORE",因为要在执行数据操作之前生成id值。

<insert id="insertTest" useGeneratedKeys="true" keyProperty="id"  parameterType="com.kq.domain.IdentityTest"> 
<selectKey keyProperty="id" resultType="String" order="BEFORE">       
SELECT  REPLACE(UUID(),'-','')    
</selectKey>        
insert into identity_test(name)        values(#{name,jdbcType=VARCHAR})
</insert>

如有错漏之处,敬请指正