以下是 2025年MyBatis高频面试题及详细解答,覆盖核心原理、实战应用、性能优化、高级特性等面试重点,适合中高级Java工程师求职备考:
解答: MyBatis是一款基于Java的持久层框架,前身是iBatis,专注于SQL映射(将Java对象与SQL语句关联),简化JDBC开发流程(无需手动处理Connection、Statement、ResultSet等对象的创建/关闭)。 核心优势:
<if> <where>)灵活拼接SQL,适配多条件查询。解答:
对比维度 | MyBatis | Hibernate |
|---|---|---|
ORM类型 | 半自动化(SQL手动编写) | 全自动化(SQL自动生成) |
SQL控制度 | 高(灵活优化复杂SQL) | 低(难优化复杂SQL) |
学习成本 | 低(专注SQL映射) | 高(需掌握HQL、缓存等) |
适用场景 | 复杂SQL、性能要求高、互联网项目 | 简单CRUD、快速开发、企业级应用 |
解答: MyBatis核心组件通过“职责链模式”协同工作,核心包括:
SqlSessionFactoryBuilder读取配置文件(mybatis-config.xml)创建,用于生成SqlSession;selectOne() insert()),线程不安全,需用完关闭;<select> <insert> <resultMap>等标签);SimpleExecutor(默认,简单执行)、ReuseExecutor(复用Statement)、BatchExecutor(批量执行);解答:
SqlSessionFactoryBuilder读取mybatis-config.xml(全局配置)和Mapper.xml(SQL映射),解析后生成SqlSessionFactory;SqlSessionFactory.openSession()创建SqlSession(默认不自动提交事务);SqlSession.getMapper(Mapper接口.class)通过JDK动态代理生成Mapper接口的代理对象;Executor执行,Executor通过StatementHandler处理JDBC操作: ResultSetHandler将ResultSet映射为Java对象;SqlSession(释放数据库连接)。解答:
对比维度 | #{} | ${} |
|---|---|---|
本质 | 预编译参数占位符(?) | 字符串拼接 |
安全性 | 防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(注入风险)。
结论:优先用#{},仅动态表名/列名时用${}(需手动过滤参数,避免注入)。解答:MyBatis支持4种多参数传递方式,核心是“让MyBatis识别参数名”:
@Param("参数名"),Mapper.xml中直接通过#{参数名}引用:User selectByUsernameAndAge(@Param("username") String username, @Param("age") int age);<select id="selectByUsernameAndAge" resultType="User">
select * from user where username = #{username} and age = #{age}
</select>#{map的key}引用(不推荐,可读性差);#{实体类属性名}引用(适合参数较多场景);#{arg0} #{arg1}或#{param1} #{param2}引用(arg从0开始,param从1开始)。解答:
ResultMap是MyBatis中结果集映射的核心标签,用于定义Java对象与数据库表字段的映射关系(解决“字段名与属性名不一致”问题)。
使用场景:
user_name vs 实体userName);AS别名(简化SQL)。
示例:<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是MyBatis的核心特性,通过标签拼接灵活的SQL语句,常用标签:
<if>:条件判断(满足条件才拼接SQL片段);<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语句,自动去除结尾的,(适配动态更新字段);<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>:遍历集合/数组(如批量查询、批量插入);<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,只执行一个满足条件的片段。解答: MyBatis缓存是为了减少数据库查询次数,提升性能,分为两级缓存:
对比维度 | 一级缓存(SqlSession级别) | 二级缓存(Mapper级别) |
|---|---|---|
作用范围 | 单个SqlSession(会话内有效) | 同一个Mapper接口(跨SqlSession) |
存储介质 | 内存(HashMap) | 内存/第三方缓存(如Redis) |
默认状态 | 开启(无法关闭) | 关闭(需手动开启) |
失效场景 | SqlSession关闭/提交/回滚;执行update/delete/insert操作 | 对应表执行增删改操作;缓存过期;手动清除 |
二级缓存启用步骤:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings><cache>标签(开启当前Mapper的二级缓存):<cache eviction="LRU" flushInterval="60000" size="1024" readOnly="true"/>eviction:缓存回收策略(LRU:最近最少使用,默认;FIFO:先进先出);flushInterval:缓存过期时间(毫秒);size:缓存最大条目数;readOnly:是否只读(true:返回缓存对象本身,性能高;false:返回拷贝对象,安全)。Serializable接口(二级缓存可能序列化存储)。注意:二级缓存适合查询频繁、修改少的场景;多表关联查询不建议用(缓存失效难以控制)。
解答:
SELECT *,只查询需要的字段;PageHelper,避免一次性查询大量数据)。ResultMap替代resultType(解决字段名不一致,避免AS别名);<result>标签fetchType="lazy")。BatchExecutor(需手动设置SqlSessionFactory.openSession(ExecutorType.BATCH));ReuseExecutor(适合频繁执行相同SQL的场景)。<if>标签(可读性差,可拆分SQL);<where> <set>替代手动拼接AND/OR和,。解答: 延迟加载是指关联查询时,只查询主表数据,关联表数据在需要时才查询(避免不必要的关联查询,提升性能)。MyBatis默认关闭懒加载,需手动开启。
实现步骤:
<settings>
<setting name="lazyLoadingEnabled" value="true"/> <!-- 开启全局懒加载 -->
<setting name="aggressiveLazyLoading" value="false"/> <!-- 关闭积极加载(按需加载) -->
</settings>association、一对多collection),设置fetchType="lazy":<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的查询。
解答:Spring Boot通过mybatis-spring-boot-starter简化MyBatis集成,核心步骤:
<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>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日志@MapperScan(扫描Mapper接口):@SpringBootApplication
@MapperScan("com.example.mapper") // Mapper接口所在包
public class MyBatisDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MyBatisDemoApplication.class, args);
}
}@Autowired
private UserMapper userMapper;
public User getUserById(Long id) {
return userMapper.selectById(id);
}解答:该异常是MyBatis最常见异常,核心原因是“Mapper接口与Mapper.xml未正确绑定”,排查方向:
namespace不一致;<select> <insert>等标签的id不一致;mybatis.mapper-locations配置错误);parameterType/resultType不匹配。解答:常见原因:
PageHelper.startPage(pageNum, pageSize));List,但未用Page对象接收(Page<User> page = (Page<User>) userMapper.selectAll());<where>标签未正确闭合)。MyBatis面试核心围绕“原理+实战+优化”,重点掌握SqlSession工作流程、动态SQL、缓存机制、参数传递、Spring Boot集成等知识点,同时结合实际项目经验,能解释常见异常排查和性能优化场景,即可应对大部分面试场景。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。