SSM框架面试题Mybatis深度解析与实战指南
在Java后端开发面试中,SSM框架面试题Mybatis 是考察候选人数据库操作能力、ORM框架理解深度以及性能优化意识的核心环节。本页面汇集了从基础原理到源码级别的深度解析,旨在帮助开发者构建完整的知识体系。
一、Mybatis核心原理与执行流程
理解 Mybatis 的核心执行流程是回答所有高级面试题的基础。Mybatis 是一个半自动化的 ORM 框架,它封装了 JDBC 操作,通过 XML 或注解将 SQL 语句与 Java 对象进行映射。
1.1 核心执行流程图解
当我们在代码中调用 SqlSession.selectList() 或 insert() 时,底层经历了以下关键步骤:
mybatis-config.xml 全局配置文件和 Mapper.xml 映射文件,构建 Configuration 对象。SqlSessionFactoryBuilder 根据 Configuration 对象构建 SqlSessionFactory 工厂实例。SqlSessionFactory 创建 SqlSession 实例,它是执行SQL的唯一入口。SqlSession 的代理对象执行具体的 SQL 映射语句。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>