首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

MyBatis vs iBATIS 核心差異深度解析:從介面綁定到動態 SQL

     編輯:Java 相關知識

前言

iBATIS 2.x 時代以 SQL 映射聞名,2010 年更名為 MyBatis 3 並遷移至 Apache。雖核心理念「SQL 獨立於程式碼」不變,但 MyBatis 在介面綁定、動態 SQL、型別處理、緩存、插件機制等方面進行重大重構。本文系統梳理核心差異,助你平滑遷移或技術選型。

核心差異總覽

維度iBATIS 2.xMyBatis 3影響
DAO 開發模式繼承 SqlMapClientDaoSupport,手寫實作類介面綁定:Mapper 介面 + 註解/XML,自動代理實作極大減少樣板碼,支援多態、單元測試
動態 SQL<isEqual>、<iterate> 等標籤OGNL 表達式:<if>、<choose>、<where>、<trim>、<foreach>功能更強、語法更簡潔、支援複雜條件組合
關聯映射嵌套查詢(N+1 問題嚴重)嵌套結果映射:<resultMap> + <association>/<collection>單查詢完成物件圖組裝,效能提升數量級
型別處理TypeHandler 介面TypeHandler 介面 + 自動掃描註冊、@MappedTypes、@MappedJdbcTypes擴充更簡單,支援 Java 8 時間類型、Enum、JSON 等
緩存機制簡單二級緩存多層緩存:一級 (Session) + 二級 (Mapper) + 第三方整合更靈活的緩存策略,支援 Ehcache、Redis、Caffeine
插件/攔截器無Interceptor 鏈:攔截 Executor、StatementHandler、ParameterHandler、ResultSetHandler分頁、加密、審計、多租戶等橫切關注點零侵入
配置方式純 XMLXML + 註解 + Java API (Configuration)微服務、Spring Boot 整合更自然
最低 JDK1.4+8+ (3.5+)享受 Lambda、Stream、Optional 等現代特性

重點解析

1. 介面綁定——最大改變

iBATIS 需手寫 UserDaoImpl extends SqlMapClientDaoSupport,MyBatis 僅需:

// Mapper 介面
public interface UserMapper {
    @Select("SELECT * FROM user WHERE id = #{id}")
    User selectById(Long id);

    @Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);

    List<User> selectByCondition(@Param("cond") UserCondition cond); // XML 對應
}

MyBatis 以 MapperProxy 動態代理介面,執行時解析註解或 XML 中的 <select id="selectByCondition">,零樣板碼。

2. 嵌套結果映射解決 N+1

iBATIS 僅支援 <resultMap> + <statement> 發起子查詢。MyBatis 引入 <association> (一對一) 與 <collection> (一對多):

<resultMap id="userMap" type="User">
    <id property="id" column="u_id"/>
    <result property="name" column="u_name"/>
    <association property="profile" javaType="Profile">
        <id property="id" column="p_id"/>
        <result property="bio" column="p_bio"/>
    </association>
    <collection property="roles" ofType="Role">
        <id property="id" column="r_id"/>
        <result property="name" column="r_name"/>
    </collection>
</resultMap>

<select id="selectUserWithDetails" resultMap="userMap">
    SELECT u.id u_id, u.name u_name,
           p.id p_id, p.bio p_bio,
           r.id r_id, r.name r_name
    FROM user u
    LEFT JOIN profile p ON u.id = p.user_id
    LEFT JOIN user_role ur ON u.id = ur.user_id
    LEFT JOIN role r ON ur.role_id = r.id
    WHERE u.id = #{id}
</select>

單條 SQL 完成物件圖組裝,避免 N+1。注意:一對多集合映射不支援分頁(MyBatis 限制),需改用嵌套查詢或應用層分頁。

3. OGNL 動態 SQL

MyBatis 採用 OGNL,表達力遠超 iBATIS:

<select id="selectByCondition" resultType="User">
    SELECT * FROM user
    <where>
        <if test="cond.name != null">AND name LIKE CONCAT('%', #{cond.name}, '%')</if>
        <if test="cond.age != null">AND age = #{cond.age}</if>
        <if test="cond.roles != null and cond.roles.size() > 0">
            AND id IN
            <foreach collection="cond.roles" item="roleId" open="(" separator="," close=")">
                #{roleId}
            </foreach>
        </if>
    </where>
    ORDER BY create_time DESC
</select>
  • <where> 自動處理首個 AND/OR
  • <trim> 更精細控制前後綴
  • <foreach> 遍歷集合/陣列/Map,支援 index 變數

4. 插件機制實現分頁

MyBatis 最經典插件場景——分頁攔截器:

@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class PaginationInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 獲取 MappedStatement、參數、RowBounds
        // 修改 SQL 加上 LIMIT/OFFSET 或 Oracle ROWNUM
        return invocation.proceed();
    }
    @Override public Object plugin(Object target) { return Plugin.wrap(target, this); }
    @Override public void setProperties(Properties properties) {}
}

註冊後,所有 selectList 自動獲得分頁能力,業務碼零侵入。

遷移清單

  1. 將 SqlMapConfig.xml → mybatis-config.xml,命名空間更新為 https://mybatis.org/schema/mybatis-3-config.xsd。
  2. DAO 介面化:刪除 *Impl 類,保留介面 + XML/註解。
  3. 動態 SQL 標籤替換:isEqual→if test、iterate→foreach、isNotEmpty→if test="list != null and list.size()>0"。
  4. 參數映射:#param# → #{param},$param$ → ${param}(原樣輸出,慎用防注入)。
  5. 型別處理器:實作 TypeHandler<T>,註解 @MappedTypes、@MappedJdbcTypes,配置 <typeHandlers>。
  6. 緩存配置:<cache> 標籤屬性調整,引入第三方緩存需實作 Cache 介面。

結語

MyBatis 不僅是 iBATIS 的改名版,更是針對 Java 現代開發(介面導向、註解驅動、插件擴展、OGNL 表達式)的全面重構。掌握介面綁定、嵌套結果映射、動態 SQL 與插件機制四大核心,即可發揮 MyBatis 最大價值:SQL 完全可控、物件映射零樣板、橫切關注點零侵入。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved