首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >java最新myBatis面试题及解答

java最新myBatis面试题及解答

原创
作者头像
小焱
发布2025-11-13 08:28:29
发布2025-11-13 08:28:29
1200
举报
文章被收录于专栏:Java开发Java开发

以下是 2025年MyBatis高频面试题及详细解答,覆盖核心原理、实战应用、性能优化、高级特性等面试重点,适合中高级Java工程师求职备考:

一、基础概念类
1. 什么是MyBatis?它的核心优势是什么?

解答: MyBatis是一款基于Java的持久层框架,前身是iBatis,专注于SQL映射(将Java对象与SQL语句关联),简化JDBC开发流程(无需手动处理Connection、Statement、ResultSet等对象的创建/关闭)。 核心优势:

  • 半自动化ORM:SQL语句需手动编写,灵活可控(适合复杂SQL场景);
  • 低侵入性:无需实体类继承特定父类或实现接口;
  • 易于整合:无缝集成Spring、Spring Boot等主流框架;
  • 缓存机制:内置一级缓存(SqlSession级别)和二级缓存(Mapper级别),提升查询效率;
  • 动态SQL:通过标签(如​​<if>​​ ​​<where>​​)灵活拼接SQL,适配多条件查询。
2. MyBatis与Hibernate的区别?适用场景是什么?

解答

对比维度

MyBatis

Hibernate

ORM类型

半自动化(SQL手动编写)

全自动化(SQL自动生成)

SQL控制度

高(灵活优化复杂SQL)

低(难优化复杂SQL)

学习成本

低(专注SQL映射)

高(需掌握HQL、缓存等)

适用场景

复杂SQL、性能要求高、互联网项目

简单CRUD、快速开发、企业级应用

二、核心原理类
3. MyBatis的核心组件有哪些?各自作用是什么?

解答: MyBatis核心组件通过“职责链模式”协同工作,核心包括:

  • SqlSessionFactory:工厂类,由​​SqlSessionFactoryBuilder​​读取配置文件(mybatis-config.xml)创建,用于生成SqlSession;
  • SqlSession:会话对象,代表与数据库的一次连接,提供CRUD操作的API(如​​selectOne()​​ ​​insert()​​),线程不安全,需用完关闭;
  • Mapper接口:自定义DAO接口,MyBatis通过动态代理生成实现类,无需手动编写Impl;
  • Mapper.xml:SQL映射文件,存储SQL语句、参数映射、结果集映射(​​<select>​​ ​​<insert>​​ ​​<resultMap>​​等标签);
  • Executor:执行器(MyBatis核心执行引擎),负责SQL解析、参数处理、结果映射,分为​​SimpleExecutor​​(默认,简单执行)、​​ReuseExecutor​​(复用Statement)、​​BatchExecutor​​(批量执行);
  • StatementHandler:处理JDBC Statement对象,负责参数设置、SQL执行、结果集封装;
  • ResultSetHandler:将JDBC ResultSet映射为Java对象。
4. MyBatis的工作原理(执行流程)是什么?

解答

  1. 加载配置:​​SqlSessionFactoryBuilder​​读取​​mybatis-config.xml​​(全局配置)和​​Mapper.xml​​(SQL映射),解析后生成​​SqlSessionFactory​​;
  2. 创建会话:通过​​SqlSessionFactory.openSession()​​创建​​SqlSession​​(默认不自动提交事务);
  3. 获取代理:​​SqlSession.getMapper(Mapper接口.class)​​通过JDK动态代理生成Mapper接口的代理对象;
  4. 执行SQL:调用Mapper接口方法,代理对象触发​​Executor​​执行,​​Executor​​通过​​StatementHandler​​处理JDBC操作:
  • 解析SQL(处理动态SQL、参数占位符);
  • 绑定参数(将Java对象参数设置到PreparedStatement);
  • 执行SQL,获取ResultSet;
  • ​ResultSetHandler​​将ResultSet映射为Java对象;
  1. 关闭会话:执行完成后,关闭​​SqlSession​​(释放数据库连接)。
三、实战应用类
5. MyBatis中#{}和${}的区别?为什么推荐用#{}?

解答

对比维度

#{}

${}

本质

预编译参数占位符(?)

字符串拼接

安全性

防SQL注入(参数自动转义)

存在SQL注入风险(直接拼接)

适用场景

传递参数(如查询条件、新增字段值)

动态表名、动态列名(如​​ORDER BY ${column}​​)

示例

  • ​select * from user where id = #{id}​​ → 编译为​​select * from user where id = ?​​(参数通过​​setInt()​​设置,安全);
  • ​select * from user where id = ${id}​​ → 若id传入​​1 or 1=1​​,则拼接为​​select * from user where id = 1 or 1=1​​(注入风险)。 结论:优先用​​#{}​​,仅动态表名/列名时用​​${}​​(需手动过滤参数,避免注入)。
6. MyBatis如何实现多参数传递?

解答:MyBatis支持4种多参数传递方式,核心是“让MyBatis识别参数名”:

  1. @Param注解(推荐):在Mapper接口方法参数上添加​​@Param("参数名")​​,Mapper.xml中直接通过​​#{参数名}​​引用:
代码语言:javascript
复制
User selectByUsernameAndAge(@Param("username") String username, @Param("age") int age);
代码语言:javascript
复制
<select id="selectByUsernameAndAge" resultType="User">
  select * from user where username = #{username} and age = #{age}
</select>
  1. Map传递:参数封装为Map,Mapper.xml通过​​#{map的key}​​引用(不推荐,可读性差);
  2. 实体类传递:参数为自定义实体类,Mapper.xml通过​​#{实体类属性名}​​引用(适合参数较多场景);
  3. 默认参数名(MyBatis 3.4+):无需注解,直接用​​#{arg0} #{arg1}​​​或​​#{param1} #{param2}​​引用(arg从0开始,param从1开始)。
7. 什么是ResultMap?为什么要用它?

解答: ​​​ResultMap​​是MyBatis中结果集映射的核心标签,用于定义Java对象与数据库表字段的映射关系(解决“字段名与属性名不一致”问题)。 使用场景

  • 数据库字段名与实体类属性名不同(如数据库​​user_name​​​ vs 实体​​userName​​);
  • 复杂查询(多表关联、嵌套查询、集合属性映射);
  • 避免SQL中写​​AS​​​别名(简化SQL)。 示例
代码语言:javascript
复制
<resultMap id="UserResultMap" type="User">
  <id column="user_id" property="userId"/> <!-- 主键映射 -->
  <result column="user_name" property="userName"/> <!-- 普通字段映射 -->
  <result column="create_time" property="createTime" jdbcType="TIMESTAMP"/> <!-- 类型指定 -->
</resultMap>

<select id="selectById" resultMap="UserResultMap">
  select user_id, user_name, create_time from user where user_id = #{id}
</select>
四、动态SQL类
8. MyBatis动态SQL的常用标签有哪些?各自作用是什么?

解答:动态SQL是MyBatis的核心特性,通过标签拼接灵活的SQL语句,常用标签:

  • ​<if>​​:条件判断(满足条件才拼接SQL片段);
代码语言:javascript
复制
<where>
  <if test="username != null and username != ''">
    and username like concat('%', #{username}, '%')
  </if>
  <if test="age != null">
    and age = #{age}
  </if>
</where>
  • ​<where>​​​:替代SQL中的​​WHERE​​​关键字,自动去除开头的​​AND/OR​​(避免拼接错误);
  • ​<set>​​​:用于​​UPDATE​​​语句,自动去除结尾的​​,​​(适配动态更新字段);
代码语言:javascript
复制
<update id="updateUser">
  update user
  <set>
    <if test="userName != null">user_name = #{userName},</if>
    <if test="age != null">age = #{age},</if>
  </set>
  where user_id = #{userId}
</update>
  • ​<foreach>​​:遍历集合/数组(如批量查询、批量插入);
代码语言:javascript
复制
<select id="selectByIds" resultType="User">
  select * from user where user_id in
  <foreach collection="ids" item="id" open="(" close=")" separator=",">
    #{id}
  </foreach>
</select>
  • (​​collection​​​:集合参数名;​​item​​​:遍历元素别名;​​open​​​:拼接开头;​​close​​​:拼接结尾;​​separator​​:元素分隔符)
  • ​<choose>​​​ ​​<when>​​​ ​​<otherwise>​​​:类似Java的​​switch-case​​,只执行一个满足条件的片段。
五、缓存机制类
9. MyBatis的一级缓存和二级缓存有什么区别?如何使用二级缓存?

解答: MyBatis缓存是为了减少数据库查询次数,提升性能,分为两级缓存:

对比维度

一级缓存(SqlSession级别)

二级缓存(Mapper级别)

作用范围

单个SqlSession(会话内有效)

同一个Mapper接口(跨SqlSession)

存储介质

内存(HashMap)

内存/第三方缓存(如Redis)

默认状态

开启(无法关闭)

关闭(需手动开启)

失效场景

SqlSession关闭/提交/回滚;执行update/delete/insert操作

对应表执行增删改操作;缓存过期;手动清除

二级缓存启用步骤

  1. 全局配置文件开启二级缓存(默认已开启,可省略):
代码语言:javascript
复制
<settings>
  <setting name="cacheEnabled" value="true"/>
</settings>
  1. Mapper.xml中添加​​<cache>​​标签(开启当前Mapper的二级缓存):
代码语言:javascript
复制
<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="true"/>
  • ​eviction​​:缓存回收策略(LRU:最近最少使用,默认;FIFO:先进先出);
  • ​flushInterval​​:缓存过期时间(毫秒);
  • ​size​​:缓存最大条目数;
  • ​readOnly​​:是否只读(true:返回缓存对象本身,性能高;false:返回拷贝对象,安全)。
  1. 实体类需实现​​Serializable​​接口(二级缓存可能序列化存储)。

注意:二级缓存适合查询频繁、修改少的场景;多表关联查询不建议用(缓存失效难以控制)。

六、性能优化类
10. MyBatis的性能优化手段有哪些?

解答

  1. SQL优化
  • 避免​​SELECT *​​,只查询需要的字段;
  • 复杂查询用索引(匹配SQL的WHERE、JOIN条件);
  • 分页查询(用MyBatis分页插件​​PageHelper​​,避免一次性查询大量数据)。
  1. 缓存优化
  • 合理使用二级缓存(查询频繁的Mapper开启);
  • 多表关联查询禁用二级缓存(或手动控制缓存失效);
  • 自定义缓存(如集成Redis,替代默认内存缓存,支持分布式场景)。
  1. 参数与结果映射优化
  • 用​​ResultMap​​​替代​​resultType​​​(解决字段名不一致,避免​​AS​​别名);
  • 大字段(如TEXT)延迟加载(通过​​<result>​​​标签​​fetchType="lazy"​​)。
  1. 执行器优化
  • 批量插入/更新用​​BatchExecutor​​​(需手动设置​​SqlSessionFactory.openSession(ExecutorType.BATCH)​​);
  • 复用Statement用​​ReuseExecutor​​(适合频繁执行相同SQL的场景)。
  1. 连接池优化
  • 整合第三方连接池(如Druid、HikariCP,替代MyBatis默认连接池),配置合理的最大连接数、空闲时间。
  1. 动态SQL优化
  • 避免复杂嵌套的​​<if>​​标签(可读性差,可拆分SQL);
  • 用​​<where>​​​ ​​<set>​​​替代手动拼接​​AND/OR​​​和​​,​​。
七、高级特性类
11. MyBatis的延迟加载(懒加载)是什么?如何实现?

解答: 延迟加载是指关联查询时,只查询主表数据,关联表数据在需要时才查询(避免不必要的关联查询,提升性能)。MyBatis默认关闭懒加载,需手动开启。

实现步骤

  1. 全局配置文件开启懒加载:
代码语言:javascript
复制
<settings>
  <setting name="lazyLoadingEnabled" value="true"/> <!-- 开启全局懒加载 -->
  <setting name="aggressiveLazyLoading" value="false"/> <!-- 关闭积极加载(按需加载) -->
</settings>
  1. Mapper.xml中定义关联查询(如一对一​​association​​​、一对多​​collection​​​),设置​​fetchType="lazy"​​:
代码语言:javascript
复制
<resultMap id="UserResultMap" type="User">
  <id column="user_id" property="userId"/>
  <!-- 一对一关联:懒加载订单信息 -->
  <association property="order" column="user_id" select="selectOrderByUserId" fetchType="lazy"/>
</resultMap>

<select id="selectOrderByUserId" resultType="Order">
  select * from order where user_id = #{userId}
</select>

原理:懒加载通过动态代理实现,当访问关联属性(如​​user.getOrder()​​)时,代理对象触发关联SQL的查询。

12. MyBatis如何集成Spring Boot?核心配置是什么?

解答:Spring Boot通过​​mybatis-spring-boot-starter​​简化MyBatis集成,核心步骤:

  1. 引入依赖(Maven):
代码语言:javascript
复制
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>2.3.2</version> <!-- 适配Spring Boot版本 -->
</dependency>
<dependency>
  <groupId>com.mysql</groupId>
  <artifactId>mysql-connector-j</artifactId>
  <scope>runtime</scope>
</dependency>
  1. 配置application.yml(核心配置):
代码语言:javascript
复制
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  mapper-locations: classpath:mapper/*.xml # Mapper.xml文件路径
  type-aliases-package: com.example.entity # 实体类别名包(可省略全类名)
  configuration:
    map-underscore-to-camel-case: true # 开启下划线转驼峰(user_name → userName)
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志
  1. 启动类添加​​@MapperScan​​(扫描Mapper接口):
代码语言:javascript
复制
@SpringBootApplication
@MapperScan("com.example.mapper") // Mapper接口所在包
public class MyBatisDemoApplication {
  public static void main(String[] args) {
    SpringApplication.run(MyBatisDemoApplication.class, args);
  }
}
  1. 编写Mapper接口和Mapper.xml(与原生MyBatis一致),直接注入使用:
代码语言:javascript
复制
@Autowired
private UserMapper userMapper;

public User getUserById(Long id) {
  return userMapper.selectById(id);
}
八、问题排查类
13. MyBatis中“Invalid bound statement (not found)”异常的原因有哪些?

解答:该异常是MyBatis最常见异常,核心原因是“Mapper接口与Mapper.xml未正确绑定”,排查方向:

  1. Mapper接口的全类名与Mapper.xml的​​namespace​​不一致;
  2. Mapper接口的方法名与Mapper.xml中​​<select>​​​ ​​<insert>​​​等标签的​​id​​不一致;
  3. Mapper.xml文件路径未配置(Spring Boot中​​mybatis.mapper-locations​​配置错误);
  4. 编译后target目录中没有Mapper.xml文件(Maven项目需在pom.xml中配置资源过滤);
  5. 方法参数类型/返回值类型与Mapper.xml中​​parameterType​​​/​​resultType​​不匹配。
14. MyBatis分页查询时,为什么总返回所有数据(分页失效)?

解答:常见原因:

  1. 未配置分页插件(如PageHelper),或插件配置错误;
  2. 分页插件使用顺序错误(需在查询方法前调用​​PageHelper.startPage(pageNum, pageSize)​​);
  3. 查询方法返回值为​​List​​​,但未用​​Page​​​对象接收(​​Page<User> page = (Page<User>) userMapper.selectAll()​​);
  4. 动态SQL拼接导致分页SQL被覆盖(如​​<where>​​标签未正确闭合)。
总结

MyBatis面试核心围绕“原理+实战+优化”,重点掌握SqlSession工作流程、动态SQL、缓存机制、参数传递、Spring Boot集成等知识点,同时结合实际项目经验,能解释常见异常排查和性能优化场景,即可应对大部分面试场景。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、基础概念类
    • 1. 什么是MyBatis?它的核心优势是什么?
    • 2. MyBatis与Hibernate的区别?适用场景是什么?
  • 二、核心原理类
    • 3. MyBatis的核心组件有哪些?各自作用是什么?
    • 4. MyBatis的工作原理(执行流程)是什么?
  • 三、实战应用类
    • 5. MyBatis中#{}和${}的区别?为什么推荐用#{}?
    • 6. MyBatis如何实现多参数传递?
    • 7. 什么是ResultMap?为什么要用它?
  • 四、动态SQL类
    • 8. MyBatis动态SQL的常用标签有哪些?各自作用是什么?
  • 五、缓存机制类
    • 9. MyBatis的一级缓存和二级缓存有什么区别?如何使用二级缓存?
  • 六、性能优化类
    • 10. MyBatis的性能优化手段有哪些?
  • 七、高级特性类
    • 11. MyBatis的延迟加载(懒加载)是什么?如何实现?
    • 12. MyBatis如何集成Spring Boot?核心配置是什么?
  • 八、问题排查类
    • 13. MyBatis中“Invalid bound statement (not found)”异常的原因有哪些?
    • 14. MyBatis分页查询时,为什么总返回所有数据(分页失效)?
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档