MyBatis 參數(shù)映射機制實踐記錄
核心組件
1. SqlSessionFactory
MyBatis 的入口點是 SqlSessionFactory
,它負責(zé)創(chuàng)建 SqlSession
實例。每個 SqlSession
都代表一個與數(shù)據(jù)庫的會話,并且在該會話中可以執(zhí)行 SQL 操作。
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { // 使用 session 進行 CRUD 操作 }
2. SqlSession
SqlSession
提供了用于執(zhí)行語句、提交或回滾事務(wù)以及獲取映射器實例的方法。它是線程不安全的,因此應(yīng)該在方法作用域內(nèi)使用(即每次調(diào)用時創(chuàng)建和關(guān)閉)。
UserMapper mapper = session.getMapper(UserMapper.class); User user = mapper.getUserById(100);
3. Mapper Interface
Mapper 接口定義了與數(shù)據(jù)庫交互的方法,這些方法通常對應(yīng)于 SQL 語句。MyBatis 通過動態(tài)代理的方式實現(xiàn)了這些接口,使得你可以在代碼中像調(diào)用普通 Java 方法一樣調(diào)用它們。
public interface UserMapper { @Select("SELECT * FROM users WHERE id = #{id}") User getUserById(@Param("id") int id); }
參數(shù)處理的具體流程
ParameterHandler 和 TypeHandler
- ParameterHandler:如前所述,這是 MyBatis 處理 SQL 語句參數(shù)的核心組件。它根據(jù) SQL 語句中的占位符設(shè)置相應(yīng)的值。
- TypeHandler:用于將 Java 類型轉(zhuǎn)換為 JDBC 類型,反之亦然。你可以注冊自定義的
TypeHandler
來支持特定的數(shù)據(jù)類型。
內(nèi)部工作原理
- 解析 SQL 語句:當(dāng) MyBatis 解析 XML 或注解定義的 SQL 語句時,它會識別出所有的
#{}
和${}
占位符,并記錄下它們的位置。 - 創(chuàng)建 ParameterHandler:對于每一個需要執(zhí)行的 SQL 語句,MyBatis 都會創(chuàng)建一個
ParameterHandler
實例。這個實例包含了如何填充 SQL 語句中占位符的信息。 - 設(shè)置參數(shù)值:
ParameterHandler
會遍歷所有占位符,并根據(jù)傳入的參數(shù)對象(可以是簡單類型、Java Bean、Map 或集合)來設(shè)置對應(yīng)的值。如果參數(shù)是一個復(fù)雜類型,MyBatis 會遞歸地訪問其屬性,直到找到匹配的值。 - 應(yīng)用 TypeHandler:對于每一個參數(shù)值,MyBatis 會查找并應(yīng)用適當(dāng)?shù)?
TypeHandler
來確保正確的數(shù)據(jù)類型轉(zhuǎn)換。 - 執(zhí)行 SQL:最后,帶有正確參數(shù)值的 SQL 語句被發(fā)送到數(shù)據(jù)庫進行執(zhí)行。
參數(shù)映射的實現(xiàn)細節(jié)
單個參數(shù)
對于單個參數(shù)的情況,MyBatis 可以直接使用參數(shù)名或默認(rèn)名稱(如 param1
)。如果你希望提高代碼的可讀性,建議總是使用 @Param
注解明確指定參數(shù)名。
@Select("SELECT * FROM users WHERE id = #{userId}") User getUserById(@Param("userId") int id);
多個參數(shù)
當(dāng)有多個參數(shù)時,使用 @Param
注解是非常重要的,因為它可以讓 MyBatis 知道每個參數(shù)的名字,從而在 SQL 中通過名字引用它們。在springBoot的1.x版本/單獨使用mybatis(使用@Param注解來指定SQL語句中的參數(shù)名),因為在編譯時,生成的字節(jié)碼文件當(dāng)中,不會保留Mapper接口中方法的形參名稱,而是使用var1、var2、...這樣的形參名字,此時要獲取參數(shù)值時,就要通過@Param注解來指定SQL語句中的參數(shù)名。
@Select("SELECT * FROM orders WHERE user_id = #{userId} AND status = #{status}") List<Order> findOrdersByUserIdAndStatus(@Param("userId") int userId, @Param("status") String status);
Java Bean 或 Map 參數(shù)
對于復(fù)雜的參數(shù)類型,如 Java Bean 或 Map,MyBatis 會自動解析對象的屬性或 Map 的鍵值對,允許你在 SQL 中通過屬性名或鍵名直接引用這些值。
@Select("SELECT * FROM products WHERE category = #{category} AND price < #{maxPrice}") List<Product> findProducts(ProductCriteria criteria);
數(shù)組和集合參數(shù)
數(shù)組和集合類型的參數(shù)可以通過 <foreach>
標(biāo)簽來處理,這使得你可以遍歷集合并在 SQL 中插入多值條件。
<select id="getCategoriesByIds" resultType="Category"> SELECT * FROM categories WHERE id IN <foreach item="id" collection="ids" open="(" separator="," close=")"> #{id} </foreach> </select>
動態(tài) SQL
MyBatis 支持動態(tài) SQL,允許根據(jù)運行時條件構(gòu)造 SQL 語句。這包括使用 <if>
, <choose>
, <when>
, <otherwise>
, <trim>
, <where>
, <set>
, 和 <foreach>
標(biāo)簽。
<select id="findActiveBlogWithTitleLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = 'ACTIVE' <if test="title != null"> AND title like #{title} </if> </select>
高級特性
自定義 TypeHandler
有時你需要自定義數(shù)據(jù)類型之間的轉(zhuǎn)換邏輯。例如,處理枚舉類型或自定義日期格式。你可以通過實現(xiàn) TypeHandler
接口并注冊到 MyBatis 中來完成這一需求。
public class EnumTypeHandler<E extends Enum<E>> implements TypeHandler<E> { private final Class<E> type; public EnumTypeHandler(Class<E> type) { if (type == null) throw new IllegalArgumentException("Type argument cannot be null"); this.type = type; } @Override public void setParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { if (parameter == null) { ps.setNull(i, Types.VARCHAR); } else { ps.setString(i, parameter.name()); } } @Override public E getResult(ResultSet rs, String columnName) throws SQLException { return rs.getString(columnName) == null ? null : Enum.valueOf(type, rs.getString(columnName)); } @Override public E getResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getString(columnIndex) == null ? null : Enum.valueOf(type, rs.getString(columnIndex)); } @Override public E getResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getString(columnIndex) == null ? null : Enum.valueOf(type, cs.getString(columnIndex)); } }
然后在 MyBatis 配置文件中注冊這個 TypeHandler
:
<typeHandlers> <typeHandler javaType="com.example.MyEnum" handler="com.example.EnumTypeHandler"/> </typeHandlers>
插件機制
MyBatis 還提供了插件機制,允許開發(fā)者攔截和修改 MyBatis 的內(nèi)部行為,如攔截 SQL 執(zhí)行、結(jié)果映射等。這對于性能監(jiān)控、日志記錄等功能非常有用。
@Intercepts({@Signature(type= Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) public class ExamplePlugin implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { // 在這里添加你的邏輯 return invocation.proceed(); } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // 設(shè)置插件屬性 } }
性能優(yōu)化和最佳實踐
1. 批量操作
對于大批量的數(shù)據(jù)操作,考慮使用批量插入、更新或刪除,以減少數(shù)據(jù)庫交互次數(shù)??梢允褂?<foreach>
標(biāo)簽結(jié)合批處理功能。
<insert id="batchInsertUsers"> INSERT INTO users (name, email) VALUES <foreach collection="list" item="user" separator=","> (#{user.name}, #{user.email}) </foreach> </insert>
2. 緩存策略
合理配置一級緩存和二級緩存,避免不必要的重復(fù)查詢。一級緩存是基于 SqlSession
的,而二級緩存可以在多個 SqlSession
之間共享。
<mapper namespace="com.example.UserMapper"> <cache/> <!-- 其他映射語句 --> </mapper>
3. 減少不必要的參數(shù)傳遞
只傳遞必要的參數(shù),以減少內(nèi)存消耗和提高性能。對于復(fù)雜對象,盡量只傳遞需要的字段。
4. 文檔化和一致性
保持代碼風(fēng)格一致,并為接口和方法添加適當(dāng)?shù)奈臋n說明,有助于團隊協(xié)作和維護。
錯誤處理與調(diào)試
1. SQL 日志輸出
開啟 SQL 日志輸出可以幫助你調(diào)試和優(yōu)化 SQL 語句。MyBatis 支持多種日志框架,如 Log4j、SLF4J 等。
# log4j.properties log4j.logger.org.apache.ibatis=DEBUG log4j.logger.java.sql.Connection=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG
2. 異常處理
確保在捕獲異常時提供足夠的信息,以便快速定位問題??梢允褂?AOP 或者手動捕獲異常,并記錄詳細的錯誤信息。
try { // 數(shù)據(jù)庫操作 } catch (PersistenceException e) { logger.error("Database operation failed", e); throw e; }
到此這篇關(guān)于MyBatis 參數(shù)映射機制的文章就介紹到這了,更多相關(guān)MyBatis 參數(shù)映射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java的非對稱加密(RSA、數(shù)字簽名、數(shù)字證書)詳解
這篇文章主要介紹了Java的非對稱加密(RSA、數(shù)字簽名、數(shù)字證書)詳解,非對稱加密:加密、解密使用不同的兩把密鑰,這兩把密鑰成對,一般通信開始時通過非對稱加密將對稱加密的密鑰發(fā)送給另一方,然后雙方通過對稱加密來進行溝通,需要的朋友可以參考下2024-01-01如何從官網(wǎng)下載Hibernate jar包的方法示例
這篇文章主要介紹了如何從官網(wǎng)下載Hibernate jar包的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04深入淺析Netty 在 Dubbo 中是如何應(yīng)用的
國內(nèi)知名框架 Dubbo 底層使用的是 Netty 作為網(wǎng)絡(luò)通信,那么內(nèi)部到底是如何使用的呢?今天通過本文給大家詳細講解,對Netty 在 Dubbo中應(yīng)用相關(guān)知識感興趣的朋友跟隨小編一起看看吧2020-05-05spring?boot+mybatis-plus配置讀寫分離的操作
這篇文章主要介紹了spring?boot+mybatis-plus配置讀寫分離的操作,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2024-01-01