Mybatis面试问题梳理

1. 为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?

Hibernate属于全自动ORM映射工具,使用Hibernate查找关联对象或关联集合对象时,根据关系模型对象直接获取,Mybatis在查找关联对象或关联集合对象时,需要手动编写sql来完成。

2. #{}和${}的区别是什么?

  1. #{}是预编译处理,${}是字符串替换

总结:优先使用#{}。仅在需要动态插入SQL关键字(非值)切能保证输入安全时,才考虑使用${}

#{}(预编译占位符)

原理:会被解析为JDBC中preparedStatement的参数占位符?

安全性:能有效防止SQL注入,因为传入的值会被当作参数处理,而不是直接拼到SQL语句中

类型处理:MyBatis会根据参数类型自动进行转换(如String加单引号)

使用场景:几乎适用于所有传入参数值的地方

${}(字符串替换)

原理:会被直接替换成对应参数值,原样直接拼到SQL语句中

安全性:存在SQL注入的风险,因为传入的值直接成为SQL语句中一部分

使用场景:

动态指定ORDER BY列名 (如ORDER BY ${columnName})

动态指定表名(如 FROM ${tableName})

插入SQL语句片段

3. MyBatis工作流程

  1. 创建SqlSessionFactoryBuilder对象,调用build(inputStream)方法读取并解析配置文件,返回SqlSessionFactory对象。
  2. SqlSessionFactory创建SqlSession对象,默认开启
  3. 调用SqlSession中的api,传递Startment Id和参数,最后调用jdbc执行sql语句执行,完成封装并返回。

4. MyBatis 的工作原理

1.读取MyBaits配置文件:在mybatis-config.xml中配置MyBatis的运行环境等信息。

2.加载映射文件:SQL映射文件,在mybatis-config.xml中配加载多个映射文件,每个文件对应数据库中的一张表

3.构造会话工厂:通过mybatis的环境等配置信息构架会话工厂SqlSessionFactory。

4.创建会话对象:由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法。

5.Executor执行器:mybatis底层定义了一个Executor接口来操作数据库,它根据SqlSession传递的参数动态的生成需要执行的SQL语句,同时负责查询缓存的维护。

6.MappedStatement对象:在Executor接口中执行方法中有一个MappedStatement类型参数,主要用于存储要映射的SQL语句的id,参数等信息。

7.输入参数映射

8.输出参数映射

5. MyBatis有几种分页方式?逻辑分页(内存分页)

5.1 逻辑分页(内存分页)

(1) 使用MyBatis内置的RowBounds对象

(2) 原理:一次性查出所有满足条件的数据到内存中,然后在内存中进行分页截取

(3) 优点:实现简单

(4) 缺点:性能差(数据量大时内存消耗大、查询慢)、有OOM风险

5.2 物理分页(数据库分页)

(1)原生SQL分页:在SQL语句中直接使用数据库特定的分页语法(如MySQL的LIMIT offset,size,Oracle的ROWNUM/窗口函数)

(2)分页插件:使用第三方分页插件(如PageHelper)

(3)原理:在SQL执行前,插件根据分页参数(页码、每页条数)动态修改SQL,添加数据库特定的分页语句,让数据库只返回当前的数据

(4)优点:性能好(数据库只处理一页数据)、内存消耗小

(5)缺点:需要编写特定SQL或引入插件

6. RowBounds是一次性查询全部结果吗?为什么?

是的,RowBounds是一次性查询全部结果的逻辑分页

因为RowBounds本身只是一个参数对象(包含offset和limit),它传递给Executor。默认的Executor实现(如SimpleExecutor)在执行查询时,会忽略RowBounds的offset和limit,执行完整的SQL查询,获取所有结果集ResultSet。在将 ResultSet 映射成对象的过程中,ResultSetHandler 会根据 RowBounds 的 offset 和 limit 在内存中跳过前面的记录并只取指定条数。因此,数据库返回的是所有数据,分页是在应用层内存中完成的。

7. MyBatis 逻辑分页和物理分页的区别是什么?

特性

逻辑分页(RowBounds)

物理分页(如原生SQL LIMIT/PageHel)

执行位置

应用层内存

数据库层

SQL

执行完整的查询SQL

执行添加分页子句的SQL 如LIMIT ?

返回数据

数据库返回所有满足条件的数据

数据只返回当前查询页的数据

性能

差(占用内存,网络传输慢,慢查询),大数据量不推荐

好(只查询当前页数据)

内存风险

高(大数据量OOM风险)

实现方式

MyBatis内置(RowBounds)

SQL语句分页或使用分页插件(PageHelper)

使用场景

数据量非常小

绝大多数分页场景

8. MyBatis 是否支持延迟加载?延迟加载的原理是什么?

(1)支持延迟加载:MyBatis支持关联对象(association,collection)的延迟加载(懒加载)

(2)原理:

代理对象:当查询主对象时,MyBatis 返回的是一个动态代理对象(如 JavassistProxyFactory 或 CglibProxyFactory 生成),而不是真实的实体类对象。

拦截调用:当应用程序首次访问这个代理对象的某个延迟加载属性(如 user.getOrders())时。

触发查询:代理对象内部会拦截这个访问方法调用。

执行子查询:拦截器(通常是 LazyLoader)根据配置的关联查询 SQL 和参数,发起一次新的 SQL 查询去加载关联数据。

填充数据:将查询到的关联数据设置到代理对象中。

返回结果:之后对该属性的访问将直接返回已加载的数据。

(3)配置:需要在全局配置文件 (mybatis-config.xml) 中显式开启:

<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/> <!-- 推荐false, 按需加载 -->
</settings>

(4)注意事项:需确保延迟加载操作在同一个 SqlSession 生命周期内完成,否则可能因 Session 关闭而加载失败。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值