SSM框架面试题Mybatis深度解析与实战指南

在Java后端开发面试中,SSM框架面试题Mybatis 是考察候选人数据库操作能力、ORM框架理解深度以及性能优化意识的核心环节。本页面汇集了从基础原理到源码级别的深度解析,旨在帮助开发者构建完整的知识体系。

一、Mybatis核心原理与执行流程

理解 Mybatis 的核心执行流程是回答所有高级面试题的基础。Mybatis 是一个半自动化的 ORM 框架,它封装了 JDBC 操作,通过 XML 或注解将 SQL 语句与 Java 对象进行映射。

1.1 核心执行流程图解

当我们在代码中调用 SqlSession.selectList() 或 insert() 时,底层经历了以下关键步骤:

1. 读取配置文件
读取 mybatis-config.xml 全局配置文件和 Mapper.xml 映射文件,构建 Configuration 对象。
2. 创建 SqlSessionFactory
通过 SqlSessionFactoryBuilder 根据 Configuration 对象构建 SqlSessionFactory 工厂实例。
3. 获取 SqlSession
通过 SqlSessionFactory 创建 SqlSession 实例,它是执行SQL的唯一入口。
4. 执行SQL语句
通过 SqlSession 的代理对象执行具体的 SQL 映射语句。
5. 结果映射与事务
将 ResultSet 结果集映射为 Java 对象,并根据配置提交或回滚事务。

1.2 #{} 与 ${} 的区别

这是最基础也最重要的考点。

特性 #{} 预编译 ${} 字符串拼接
安全性 安全,防止 SQL 注入 不安全,存在 SQL 注入风险
原理 使用 PreparedStatement,替换为 ? 直接进行字符串替换
适用场景 大多数参数传入 动态表名、列名排序等

二、Mybatis 缓存机制深度解析

缓存是 Mybatis 提升性能的关键特性。面试中常问的一级缓存和二级缓存的区别,以及在实际项目中的应用场景。

一级缓存 (Local Cache)

作用域: SqlSession 级别。
默认开启: 是。
原理: 在 SqlSession 内部维护一个 Map,Key 为 SQL 语句+参数+RowBounds,Value 为查询结果。
失效场景: 执行增删改操作、手动清空缓存、不同的 SqlSession。

二级缓存 (Global Cache)

作用域: Mapper 命名空间 (Namespace) 级别。
默认开启: 否,需手动配置。
原理: 多个 SqlSession 共享同一个 Mapper 的缓存。
注意: 实体类必须实现 Serializable 接口。

2.1 二级缓存的工作原理

当开启二级缓存时,Mybatis 会在执行查询语句后,将结果存入当前 Mapper 的二级缓存中。当其他 SqlSession 执行相同的查询时,会先从二级缓存中获取,如果命中则直接返回,否则查询数据库并写入缓存。

<!-- mybatis-config.xml 配置 -->
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>
<!-- Mapper.xml 配置 -->
<mapper namespace="com.kaoacca.mapper.UserMapper">
    <cache/> <!-- 开启当前命名空间的二级缓存 -->
    <select id="selectUser" resultType="User" useCache="true">
        SELECT  FROM user WHERE id = #{id}
    </select>
</mapper>

注意: 在实际分布式项目中,通常使用 Redis 或 Memcached 作为二级缓存,因为 Mybatis 默认的二级缓存是基于内存的,不支持分布式共享。

三、Mybatis 高级特性与动态SQL

除了基础 CRUD,Mybatis 提供了丰富的动态 SQL 和插件机制,这是解决复杂业务需求的关键。

3.1 动态 SQL 标签详解

  • <if>: 条件判断,用于单个条件判断。
  • <choose>、<when>、<otherwise>: 类似于 Java 的 switch-case 语句。
  • <where>: 自动处理 SQL 中的 WHERE 关键字,并去除多余的 AND/OR。
  • <trim>: 自定义去除前缀或后缀,比 <where> 更灵活。
  • <foreach>: 用于集合遍历,常用于 IN 查询或批量插入。
  • <bind>: 创建一个变量供后续使用,常用于模糊查询。

3.2 插件 (Interceptor) 原理

Mybatis 的插件是基于 Java 动态代理 实现的。它允许开发者拦截 Executor、ParameterHandler、ResultSetHandler 和 StatementHandler 这四个核心接口的关键方法。

拦截对象 作用 常见场景
Executor 拦截更新、查询、提交等操作 分页插件、缓存插件
ParameterHandler 拦截参数设置 参数加密、脱敏
ResultSetHandler 拦截结果集处理 结果集转换、字段映射
StatementHandler 拦截 SQL 语句的组装 SQL 改写、分页 SQL 拼接

四、SSM框架面试题Mybatis 性能优化策略

性能优化是高级开发面试的必考题。针对 Mybatis 的性能优化,可以从数据库、框架配置、SQL 编写等多个维度进行。

1. SQL 优化

避免 SELECT ,只查询需要的字段;使用覆盖索引;避免在索引列上做计算或函数操作;合理使用 EXPLAIN 分析执行计划。

2. 批量操作

避免在循环中执行 SQL,使用 <foreach> 进行批量插入或更新,减少数据库连接开销。

3. 缓存使用

合理开启一级/二级缓存,或在业务层使用 Redis 缓存热点数据,减轻数据库压力。

4. 连接池配置

使用 HikariCP 等高性能连接池,合理配置最大连接数、最小空闲连接数等参数。

4.1 懒加载 (Lazy Loading)

在关联查询中,默认情况下 Mybatis 会立即加载所有关联对象。开启懒加载后,只有在真正使用关联对象时才会发起查询。

<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

五、Mybatis 源码核心解析

深入源码是理解 Mybatis 运行机制的关键。重点关注 SqlSessionFactory 的构建过程和 SqlSession 的代理实现。

5.1 Mapper 代理对象的生成

Mybatis 使用 JdkDynamicAopProxy 或 CglibAopProxy 生成 Mapper 接口的代理对象。当调用 Mapper 方法时,代理对象会拦截调用,并将方法名和参数封装成 MappedStatement,最终通过 SqlSession 执行 SQL。

5.2 MappedStatement 对象

MappedStatement 是 Mybatis 内部最核心的对象之一,它封装了 SQL 语句、输入参数映射、输出结果映射等信息。每一个 SQL 标签(select/insert/update/delete)都会对应一个 MappedStatement 对象,存储在 Configuration 的 mappedStatements Map 中。

六、网友们还关心:Mybatis 高频面试题 Q&A

以下整理了近期求职者最关心的 SSM框架面试题Mybatis 相关问题,并提供深度解答。

Q1: Mybatis 如何防止 SQL 注入?

Mybatis 主要通过 #{} 预编译机制来防止 SQL 注入。预编译会将 SQL 语句中的参数部分替换为占位符 ?,然后在执行前由数据库驱动进行类型检查和转义,从而避免恶意代码注入。而 ${} 是字符串拼接,无法防止 SQL 注入,应尽量避免使用。

Q2: 一对一、一对多关联查询怎么做?

使用 <association> 标签处理一对一关联,使用 <collection> 标签处理一对多关联。可以通过嵌套查询(select 属性)或嵌套结果(resultMap)两种方式实现。嵌套查询会产生 N+1 问题,建议在生产环境中使用嵌套结果或开启懒加载。

Q3: Mybatis 和 Hibernate 的区别?

1. 自动化程度: Hibernate 是全自动化 ORM 框架,Mybatis 是半自动化。
2. SQL 编写: Mybatis 需要手动编写 SQL,灵活性强;Hibernate 自动生成 SQL,简单场景方便。
3. 缓存: Hibernate 一级/二级缓存更完善;Mybatis 缓存需手动配置。
4. 学习曲线: Mybatis 简单易学;Hibernate 学习曲线陡峭。

七、周边知识拓展:Spring 与 Mybatis 的整合

在 SSM 框架中,Spring 负责管理 Bean 的生命周期,Mybatis 负责数据访问。两者的整合主要通过 SqlSessionFactoryBean 和 MapperScannerConfigurer 实现。

1. SqlSessionFactoryBean

用于创建 SqlSessionFactory。它可以配置数据源、Mybatis 全局配置、Mapper 文件位置等。

2. MapperScannerConfigurer

用于自动扫描 Mapper 接口,并将它们注册为 Spring Bean。它会自动创建 Mapper 接口的代理对象,并将其注入到容器中。

7.1 事务管理整合

Spring 通过 PlatformTransactionManager 管理事务。在 Mybatis 中,SqlSession 的事务由 Spring 的 TransactionSynchronizationManager 管理,确保多个 SqlSession 共享同一个数据库事务连接。

<!-- Spring 配置文件示例 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations" value="classpath:mapper/.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.kaoacca.mapper"/>
</bean>