Mybatis 面试题
# Mybatis 面试
# 什么是 ORM 框架?
用于实现面向对象编程语言里不同系统的数据之间的转换
# 什么是 MyBatis?
答:MyBatis 是一个可以自定义 SQL、存储过程和高级映射的持久层框架。
# 讲下 MyBatis 的缓存?
答:MyBatis 的缓存分为一级缓存和二级缓存,一级缓存放在 session 里面,默认就有,二级缓存放在它的命名空间里,默认是不打开的,使用二级缓存属性类需要实现 Serializable 序列化接口(可用来保存对象的状态),可在它的映射文件中配置<cache/>
# Mybatis 是如何进行分页的?分页插件的原理是什么?
1)、Mybatis 使用 RowBounds 对象进行分页,也可以直接编写 sql 实现分页,也可以使用 Mybatis 的分页插件。
2)、分页插件的原理:实现 Mybatis 提供的接口,实现自定义插件,在插件的拦截方法内拦 截待执行的 sql,然后重写 sql。
举例:select * from student,拦截 sql 后重写为:select t.* from (select * from student)t limit 0,10
# 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 的功能。
# #{}和${}的区别是什么?
#{}
是预编译处理,${}
是字符串替换。- Mybatis 在处理
#{}
时,会将 sql 中的#{}
替换为 ? 号,调用 PreparedStatement 的 set 方法来赋值; - Mybatis 在处理
${}
时,就是把${}
替换成变量的值。#{}
会有数据类型的处理,比如字符串会加引号处理,当替换表名这类场景时,就会存在问题,需要使用${}
- 使用
#{}
可以有效的防止 SQL 注入,提高系统安全性。
# 为什么说 Mybatis 是半自动 ORM 映射工具? 它与全自动的区别在哪里?
Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象 时,可以根据对象关系模型直接获取,所以它是全自动的。而 Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,所以,称之为半自动 ORM 映射工具。
# 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()方法的调用。这就是延迟加载的基本原理。
# 什么是 MyBatis 的接口绑定,有什么好处?
接口映射就是在 MyBatis 中任意定义接口,然后把接口里面的方法和 SQL 语句绑定,我们直接调用接口方法就可以,这样比起原来了 SqlSession 提供的方法我们可以有更加灵活的选择和设置。
# Mybatis 是如何将 sql 执行结果封装为目标对象并返回的?都有哪些映射形式?
第一种是使用<resultMap>
标签,逐一定义列名和对象属性名之间的映射关系。
第二种是使用 sql 列的别名功能,将列别名书写为对象属性名,比如 T_NAME AS NAME,对 象属性名一般是 name,小写,但是列名不区分大小写,Mybatis 会忽略列名大小写,智能 找到与之对应对象属性名,你甚至可以写成 T_NAME AS NaMe,Mybatis 一样可以正常工 作。
有了列名与属性名的映射关系后,Mybatis 通过反射创建对象,同时使用反射给对象的属性 逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
# 当实体类中的属性名和表中的字段名不一样,如果将查询的结果封装到指定 pojo?
通过在查询的 sql 语句中定义字段名的别名。
通过
<resultMap>
来映射字段名和实体类属性名的一一对应的关系。
# 模糊查询 like 语句该怎么写
- 在 java 中拼接通配符,通过
#{}
赋值 - 在 Sql 语句中拼接通配符 (不安全 会引起 Sql 注入)
# Mybatis 中如何执行批处理?
使用 BatchExecutor 完成批处理。
# Mybatis 都有哪些 Executor 执行器?它们之间的区别是什么?
Mybatis 有三种基本的 Executor 执行器,SimpleExecutor、ReuseExecutor、 BatchExecutor。
SimpleExecutor:每执行一次 update 或 select,就开启一个 Statement 对 象,用完立刻关闭 Statement 对象。
ReuseExecutor:执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象, 而是放置于 Map
BatchExecutor:完成批处理。
# Mybatis 中如何指定使用哪一种 Executor 执行器?
在 Mybatis 配置文件中,可以指定默认的 ExecutorType 执行器类型,也可以手动给 DefaultSqlSessionFactory 的创建 SqlSession 的方法传递 ExecutorType 类型参数。
# 如何获取自动生成的(主)键值?
配置文件设置 usegeneratedkeys 为 true
# resultType resultMap 的区别?
类的名字和数据库相同时,可以直接设置 resultType 参数为 Pojo 类
若不同,需要设置 resultMap 将结果名字和 Pojo 名字进行转换
# 在 mapper 中如何传递多个参数?
直接在方法中传递参数,xml 文件用#{0} #{1}来获取
使用 @param 注解:这样可以直接在 xml 文件中通过#{name}来获取
# 什么叫预编译?
通过Statement对象执行SQL语句时,需要将SQL语句发送给DBMS,由DBMS首先进行编译后再执行。
预编译语句和Statement不同,在创建PreparedStatement 对象时就指定了SQL语句,该语句立即发送给DBMS进行编译。当该编译语句被执行时,DBMS直接运行编译后的SQL语句,而不需要像其他SQL语句那样首先将其编译。
# 为什么使用预编译语句
- 防止SQL注入
- 提高效率 数据库处理一个SQL语句,需要完成解析SQL语句、检查语法和语义以及生成代码,一般说来,处理时间要比执行语句所需要的时间长。预编译语句在创建的时候已经是将指定的SQL语句发送给了DBMS,完成了解析、检查、编译等工作。因此,当一个SQL语句需要执行多次时,使用预编译语句可以减少处理时间,提高执行效率。
- 提高代码的可读性和可维护性 将参数与SQL语句分离出来,这样就可以方便对程序的更改和扩展,同样,也可以减少不必要的错误。
# 在标签 <mappers>
下,有几种 mapper 加载方式?哪种方式优先级最高?
Resource、url、package、class 这四种,package 优先级最高。
# mapper 中的例如 select 语句、insert 语句都在哪里保存?
在 MappedStatement 中,是通过 addMappedStatement 方法进行初始化。
# statementType 有哪些?
Any one of STATEMENT
, PREPARED
or CALLABLE
. This causes MyBatis to use Statement
, PreparedStatement
or CallableStatement
respectively. Default: PREPARED
.
# Mybatis Spring Boot 项目中默认会检查 config.xml
文件吗?
不会,在配置类 MybatisProperties 中默认是关闭的。如果检查是在类初始化的时候进行,他实现了 InitializingBean 接口。
# SqlSessionFactoryBean 的作用是什么?
通过获取各种mybatis配置信息,用于初始化SqlSessionFactory
# Xml 配置方式、Yaml配置方式、Java 配置方式哪种优先级比较高?
Java > Yaml > Xml
# Executor 实现中使用了什么设计模式?
装饰器模式,先通过BaseExecutor实现核心功能,再由Reuse、Simple、BatchExecutor实现各自能力。
# Mybatis 工作原理?
- 读取核心配置文件并返回
InputStream
流对象。 - 根据
InputStream
流对象解析出Configuration
对象,然后创建SqlSessionFactory
工厂对象 - 根据一系列属性从
SqlSessionFactory
工厂中创建SqlSession
- 从
SqlSession
中调用Executor
执行数据库操作&&生成具体SQL指令 - 对执行结果进行二次封装
- 提交与事务