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代碼生成器