Mybatis高频面试题

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

答案

对比项 #{} ${}
处理方式 预编译占位符(?),使用 PreparedStatement 字符串直接替换,使用 Statement
安全性 防止 SQL 注入 存在 SQL 注入风险
使用场景 大部分参数传递 表名、列名、ORDER BY 等动态字段
示例 WHERE id = #{id}WHERE id = ? ORDER BY ${column}ORDER BY name

面试加分点 :优先使用 #{},只有当传入的是表名、列名、ORDER BY 等无法使用占位符的场景才用 ${}

2. MyBatis 的动态 SQL 有哪些常用标签?

答案

标签 作用 示例
<if> 条件判断 WHERE id = #{id} AND name = #{name}
<choose> 多分支选择(类似 switch) <choose><when test=...><otherwise>
<where> 自动处理 WHERE 关键字和多余的 AND/OR 包裹条件,智能加 WHERE 和去多余连接词
<set> 自动处理 SET 关键字和尾部逗号 用于 update 语句,智能加 SET 和去多余逗号
<foreach> 遍历集合 IN (#{item})
<trim> 自定义前缀、后缀及去除逻辑 更灵活的 <where> / <set> 底层实现

举例:

xml 复制代码
<update id="updateUser" parameterType="User">
    UPDATE user
    <set>
        <if test="name != null and name != ''">
            name = #{name},
        </if>
        <if test="age != null">
            age = #{age},
        </if>
        <if test="email != null and email != ''">
            email = #{email},
        </if>
    </set>
    WHERE id = #{id}
</update>

<!-- 使用 <trim> 模拟 <set> -->
<update id="updateUser">
    UPDATE user
    <trim prefix="SET" suffixOverrides=",">
        <if test="name != null">name = #{name},</if>
        <if test="age != null">age = #{age},</if>
        <if test="email != null">email = #{email},</if>
    </trim>
    WHERE id = #{id}
</update>

3. MyBatis 如何解决实体类属性名和数据库字段名不一致的问题?

答案

三种方式

  1. 使用 resultMap(推荐)

    明确指定字段与属性的映射关系:

    xml

    复制代码
    <resultMap id="UserMap" type="User">
        <result column="user_name" property="userName"/>
        <result column="phone_num" property="phoneNum"/>
    </resultMap>
  2. 使用 @Results 注解

    java

    复制代码
    @Results({
        @Result(column = "user_name", property = "userName"),
        @Result(column = "phone_num", property = "phoneNum")
    })

3、字段起别名

sql 复制代码
select user_name as userName

4. resultTyperesultMap 的区别?

答案

对比项 resultType resultMap
用途 简单映射,字段名与属性名一致时使用 复杂映射,支持不一致、嵌套对象、关联查询
灵活性
是否支持一对多/多对一 不支持 支持
推荐场景 简单查询 复杂查询、关联查询

面试加分点:resultType 是 MyBatis 的自动映射resultMap手动映射,并能支持延迟加载。

5、MyBatis 的一级缓存和二级缓存有什么区别?

特性 一级缓存 二级缓存
作用范围 SqlSession 内 Mapper 的 namespace 内
默认 开启 关闭
生命周期 会话级别 应用级别(随 SqlSessionFactory)
跨会话 不共享 共享
数据形式 对象引用 对象的副本(序列化)
清空时机 执行 DML、clearCache()、会话关闭 执行 DML(同 namespace)、会话关闭时写入
最佳实践 单个请求内的重复查询 读多写少的静态数据
一级缓存(SqlSession 级别)
java 复制代码
// 一、作用域演示
// 	同一个 SqlSession
SqlSession session = sqlSessionFactory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);

User user1 = mapper.selectById(1);  // 执行 SQL
User user2 = mapper.selectById(1);  // 命中一级缓存,不执行 SQL
session.close();

// 缓存的数据形式演示: 一级缓存:修改对象会影响缓存
User user1 = mapper.selectById(1);
user1.setName("新名字");  // 缓存里也被改了
二级缓存(NameSpace 级别)
java 复制代码
// 一、作用域演示
// 会话1
SqlSession session1 = sqlSessionFactory.openSession();
UserMapper mapper1 = session1.getMapper(UserMapper.class);
User user1 = mapper1.selectById(1);  // 执行 SQL,数据放入二级缓存
session1.close();  // 会话关闭,数据进入二级缓存
// 会话2(不同的 SqlSession)
SqlSession session2 = sqlSessionFactory.openSession();
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user2 = mapper2.selectById(1);  // 命中二级缓存,不执行 SQL
session2.close();

// 二、缓存的数据形式演示:二级缓存:修改对象不影响缓存(因为返回的是副本)
User user1 = mapper.selectById(1);
user1.setName("新名字");  // 缓存里的对象不受影响
User user2 = mapper.selectById(1);  // 返回的是新副本,name 还是旧值

6、MyBatis 如何实现分页?

方式 实现原理 性能 侵入性 配置复杂度 推荐场景
手动 Limit 手写 LIMIT 简单项目,查询少
RowBounds 全查+内存截取 极低 绝不使用
PageHelper SQL 拦截器 通用推荐
MyBatis-Plus 插件拦截 中(需要整个框架) 已用 MyBatis-Plus 的项目
java 复制代码
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    
    public PageInfo<User> getUsersByPage(int pageNum, int pageSize) {
        // 1. 设置分页参数(会拦截接下来的第一次查询)
        PageHelper.startPage(pageNum, pageSize);
        
        // 2. 执行查询(自动拼接 LIMIT)
        List<User> users = userMapper.selectAll();
        
        // 3. 包装成 PageInfo(包含总数、总页数等信息)
        PageInfo<User> pageInfo = new PageInfo<>(users);
        
        return pageInfo;
    }
}

7、MyBatis 和 JPA/Hibernate 有什么区别?

答案

对比项 MyBatis JPA/Hibernate
类型 半自动 ORM(仅映射结果集) 全自动 ORM(对象与表完全映射)
SQL 控制 完全手写 SQL,精细化控制 自动生成 SQL,可配置但难调优
学习成本 中高
开发效率 中等(需写 SQL) 高(无需写 SQL)
性能调优 容易,SQL 可针对性优化 困难,需理解 HQL 生成规则
数据库移植 差,SQL 与方言绑定 好,自动适配不同数据库
适用场景 复杂查询、高 SQL 调优需求 CRUD 为主、需求快速开发

选择建议

  • 复杂查询、对 SQL 执行计划有要求 → 选 MyBatis
  • 简单 CRUD、快速开发、数据库需要迁移 → 选 JPA/Hibernate
相关推荐
学长毕业设计3 小时前
基于SpringBoot的公益基金管理系统(源码+文档+讲解视频)
java·spring boot·后端
东小西3 小时前
【SAA实战】第 3 篇 · 工具调用全攻略:把业务能力交给 Agent 自己调度
java·后端·spring
东小西3 小时前
【SAA实战】第 4 篇 · Agent 短期记忆:saver 让 Agent 跨轮记得住(threadId 隔离)
java·后端·spring
许彰午4 小时前
22-DataCenter报文序列化
java·低代码·架构·状态模式
2601_962065254 小时前
[MySQL] SQL优化之性能分析
java·sql·mysql
小范同学_4 小时前
JDK1.7 与 JDK1.8 HashMap 底层原理对比 + 数组并发扩容死循环详解
java·开发语言
予昊5 小时前
从零实现“在线五子棋对战“:WebSocket 实时通信 + 段位匹配
java·开发语言·网络·websocket
2601_962203515 小时前
【SpringAI入门】初识SpringAI
java
weixin_461408585 小时前
Mybatis-flex小记
java·开发语言·mybatis
2601_962177136 小时前
【MySQL篇】聚合查询,联合查询
android·java·mysql