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. resultType 和 resultMap 的区别?

答案:

对比项 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
相关推荐
huaweichenai5 分钟前
spring boot实现base64上传
java·spring boot·后端
萧瑟余晖10 分钟前
Spring Web综合实战与性能调优详解
java·spring
点纭11 分钟前
spring ai1.0实战:ChatClient(2)
java·后端·spring
小马过河R15 分钟前
EdgeOne深度解析:从原理、适用场景到COS接入的技术逻辑
java·开发语言·前端·spring·cos
java水泥工36 分钟前
什么是前端
java·vue·html5
Rain的Java大神之路1 小时前
Java 工程师做 AI,核心机会在「落地」而非「训练」
java·后端·ai编程
薛之谦_1 小时前
JAVA 多线程编程:从基础原理到实战应用
java·开发语言
LMT_Lanmantech1 小时前
Creo许可降本增效:不增购,也能让现有许可发挥更大价值
java·大数据·开发语言
Shaoshing1 小时前
Serializable
java
wuminyu2 小时前
ZGC染色指针在虚拟线程stackChunkOop上的并发屏障全景分析
java·linux·c语言·jvm·c++