MyBatis从入门到面试:掌握持久层框架的精髓
前言
在Java企业级应用开发中,持久层框架的选择至关重要。MyBatis作为一款优秀的半自动化ORM框架,以其灵活的SQL定制能力和良好的性能表现,成为了众多开发者的首选。本文将带你从MyBatis的基础入门开始,逐步深入核心概念,最后为你准备面试常见问题,助你全面掌握MyBatis。
一、MyBatis入门篇
1.1 什么是MyBatis?
MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集的工作,可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO为数据库中的记录。
1.2 环境搭建与配置
首先,我们需要在项目中引入MyBatis依赖:
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version>
</dependency>
接下来创建MyBatis的核心配置文件mybatis-config.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/test"/><property name="username" value="root"/><property name="password" value="password"/></dataSource></environment></environments><mappers><mapper resource="com/example/mapper/UserMapper.xml"/></mappers>
</configuration>
1.3 第一个MyBatis程序
创建实体类:
public class User {private Long id;private String name;private String email;// 构造方法、getter和setter省略
}
创建Mapper接口:
public interface UserMapper {User selectUserById(Long id);
}
创建Mapper XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper"><select id="selectUserById" resultType="com.example.entity.User">SELECT * FROM user WHERE id = #{id}</select>
</mapper>
使用MyBatis API执行查询:
public class MyBatisExample {public static void main(String[] args) {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);try (SqlSession session = sqlSessionFactory.openSession()) {UserMapper mapper = session.getMapper(UserMapper.class);User user = mapper.selectUserById(1L);System.out.println(user.getName());}}
}
二、MyBatis核心概念解析
2.1 SqlSessionFactory与SqlSession
- SqlSessionFactory:每个MyBatis应用都以一个SqlSessionFactory实例为核心,它是线程安全的,一旦创建应在应用运行期间一直存在
- SqlSession:代表一次数据库会话,不是线程安全的,每个线程都应该有它自己的SqlSession实例
2.2 Mapper接口与XML映射文件
MyBatis通过动态代理技术将Mapper接口与XML映射文件关联起来:
// Mapper接口
public interface UserMapper {@Insert("INSERT INTO user(name, email) VALUES(#{name}, #{email})")@Options(useGeneratedKeys = true, keyProperty = "id")int insertUser(User user);@Select("SELECT * FROM user WHERE id = #{id}")User selectUserById(Long id);
}
或者使用XML配置:
<mapper namespace="com.example.mapper.UserMapper"><insert id="insertUser" parameterType="com.example.entity.User"useGeneratedKeys="true" keyProperty="id">INSERT INTO user(name, email) VALUES(#{name}, #{email})</insert>
</mapper>
2.3 动态SQL
MyBatis提供了强大的动态SQL功能:
<select id="findUsers" parameterType="map" resultType="User">SELECT * FROM user<where><if test="name != null">AND name LIKE CONCAT('%', #{name}, '%')</if><if test="email != null">AND email = #{email}</if><choose><when test="orderBy == 'name'">ORDER BY name</when><otherwise>ORDER BY id</otherwise></choose></where>
</select>
2.4 结果映射
MyBatis支持复杂的结果映射:
<resultMap id="userResultMap" type="User"><id property="id" column="id"/><result property="name" column="name"/><result property="email" column="email"/><collection property="posts" ofType="Post"><id property="id" column="post_id"/><result property="title" column="post_title"/><result property="content" column="post_content"/></collection>
</resultMap>
三、MyBatis高级特性
3.1 插件开发
MyBatis允许用户使用插件拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
示例:实现一个简单的SQL执行时间统计插件
@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class SqlExecuteTimeInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {long start = System.currentTimeMillis();Object result = invocation.proceed();long end = System.currentTimeMillis();System.out.println("执行耗时: " + (end - start) + "ms");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}
}
3.2 缓存机制
MyBatis提供两级缓存:
- 一级缓存:SqlSession级别的缓存,默认开启
- 二级缓存:Mapper级别的缓存,需要手动配置开启
<!-- 在Mapper XML中开启二级缓存 -->
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
3.3 类型处理器
自定义类型处理器处理特殊数据类型:
public class StringArrayTypeHandler extends BaseTypeHandler<String[]> {@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, String.join(",", parameter));}@Overridepublic String[] getNullableResult(ResultSet rs, String columnName) throws SQLException {String value = rs.getString(columnName);return value != null ? value.split(",") : null;}// 其他方法省略
}
四、MyBatis面试常见问题
4.1 基础概念类
1. MyBatis和Hibernate有什么区别?
- MyBatis是半自动ORM框架,需要手动编写SQL;Hibernate是全自动框架,自动生成SQL
- MyBatis更灵活,适合复杂查询和性能优化场景;Hibernate开发效率更高,适合传统CRUD操作
- MyBatis学习曲线较平缓;Hibernate学习曲线较陡峭
2. #{}和${}的区别是什么?
- #{}是预编译处理,可以有效防止SQL注入
- ${}是字符串替换,有SQL注入风险,一般用于order by等非值替换场景
4.2 高级特性类
1. MyBatis的插件运行原理是什么?
MyBatis使用责任链模式,通过动态代理组织多个插件。当执行目标方法时,会按照插件配置的顺序依次调用插件的intercept方法。
2. MyBatis如何实现分页?
- 物理分页:使用RowBounds或分页插件(如PageHelper)
- 逻辑分页:使用ResultSet的absolute方法,但数据量大时性能较差
4.3 性能优化类
1. MyBatis如何进行批量操作?
try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {UserMapper mapper = session.getMapper(UserMapper.class);for (int i = 0; i < 1000; i++) {User user = new User("name" + i, "email" + i);mapper.insertUser(user);}session.commit();
}
2. 如何优化MyBatis查询性能?
- 合理使用缓存
- 使用延迟加载
- 优化SQL语句
- 使用连接池
- 避免N+1查询问题
五、总结
MyBatis作为一个灵活、高效的持久层框架,在现代Java开发中占据重要地位。通过本文的学习,你应该已经掌握了MyBatis从基础使用到高级特性的核心知识,并为面试做好了充分准备。记住,框架只是工具,真正重要的是理解其背后的设计思想和原理,这样才能在实际项目中灵活运用,解决复杂问题。
希望这篇博客对你有所帮助,祝你学习进步,面试顺利!
延伸阅读:
- MyBatis官方文档
- MyBatis-Spring整合指南
- MyBatis Generator代码生成器