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
相关推荐
遇见你的雩风2 小时前
Java --- 网络原理(三)
java·开发语言·网络
itzixiao2 小时前
L1-058 6翻了(15分)[java][python]
java·开发语言·python·算法
直奔標竿2 小时前
Java开发者AI转型第十三课!知识库终局方案:Spring AI Vector Store架构演进与ETL全链路入库实战
java·人工智能·后端·spring
XiYang-DING2 小时前
【Java EE】阻塞队列(BlockingQueue)
java·java-ee
AndreasEmil2 小时前
基于多设计模式的抽奖系统 - 测试报告
java·selenium·设计模式·postman
星轨zb2 小时前
什么是Spring设计模式:单例、工厂与代理
java·spring·设计模式
Seven972 小时前
Tomcat Server的设计和实现:StandardServer
java
s6516654962 小时前
Makefile语法学习
java·linux·前端
Rabitebla2 小时前
二分查找(含有动画展示):不再写出死循环
java·开发语言