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

MyBatis 學習筆記(三):DAO 開發兩大模式深度解析——原始 DAO vs Mapper 動態代理

     編輯:Java 綜合教學

MyBatis 學習筆記(三):DAO 開發兩大模式深度解析——原始 DAO vs Mapper 動態代理

MyBatis 作為優秀的持久層框架,提供了兩種 DAO 開發模式:原始 DAO 開發(手寫實現類)與 Mapper 動態代理開發(僅定義接口,框架自動生成實現)。實際項目中極力推薦 Mapper 模式,本文將對比兩者優劣、剖析核心原理、給出生產級最佳實踐。

核心三大對象:SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession

對象角色最佳作用域線程安全說明
SqlSessionFactoryBuilder構建工廠的工具類方法局部變量無狀態,安全用完即丟,無需保持引用
SqlSessionFactory會話工廠,重量級應用生命周期(單例)線程安全緩存配置、映射元數據,通常作為 Bean 注入
SqlSession數據庫會話,輕量級請求/方法級非線程安全封裝 CRUD,用完必須 close,放入 finally 塊
// 正確使用模式:獲取 -> 操作 -> 關閉
SqlSession session = sqlSessionFactory.openSession();
try {
    UserMapper mapper = session.getMapper(UserMapper.class);
    User user = mapper.selectUserByID(1);
    session.commit(); // 增刪改需提交
} finally {
    session.close();
}

模式一:原始 DAO 開發(不推薦用於新項目)

程序員手寫 DAO 接口 + 實現類,實現類中注入 `SqlSessionFactory`,手動管理 `SqlSession` 生命周期,硬編碼 Statement ID。

缺點痛點

  • 模板代碼泛濫:每個方法都要 openSession、try/finally close、commit
  • Statement ID 硬編碼:字符串 "namespace.id" 易寫錯,重構困難
  • 參數類型不安全:`selectOne(String, Object)` 參數為 Object,編譯期不報錯
  • 維護成本高:增刪改查每個表都要寫一套實現類

模式二:Mapper 動態代理開發(標準姿勢)

僅定義 Mapper 接口,MyBatis 根據接口方法簽名自動生成 JDK 動態代理對象,內部委託 `SqlSession` 執行 SQL。

四大映射規範(必須一一對應)

  1. Mapper.xml 的 namespace = Mapper 接口全限定名
  2. Mapper 接口方法名 = XML 中 <select|insert|update|delete> 的 id
  3. 接口方法輸入參數類型 = XML parameterType
  4. 接口方法返回類型 = XML resultType / resultMap

實戰代碼示例

// UserMapper.xml
<mapper namespace="com.yihaomen.mybatis.dao.IUserOperation">
    <select id="selectUserByID" parameterType="int" resultType="User">
        select * from `user` where id = #{id}
    </select>
    <insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
        insert into user(userName,userAge,userAddress) values(#{userName},#{userAge},#{userAddress})
    </insert>
    <select id="findUserByName" parameterType="String" resultType="User">
        select * from `user` where username like '%${value}%'
    </select>
</mapper>
// IUserOperation.java (Mapper 接口)
public interface IUserOperation {
    User selectUserByID(int id);
    void addUser(User user);
    List<User> findUserByName(String name); // 返回 List,內部自動調用 selectList
}
// 測試代碼
SqlSession session = sqlSessionFactory.openSession();
try {
    IUserOperation mapper = session.getMapper(IUserOperation.class);
    User user = mapper.selectUserByID(1); // 直接調用接口方法,無需寫 SQL ID
    List<User> list = mapper.findUserByName("小");
    session.commit();
} finally {
    session.close();
}

進階避坑指南

  • 返回類型自適應:Mapper 方法返回 `List` 時,代理內部自動判斷調用 `selectList`;返回單一 POJO 時調用 `selectOne`,無需開發者關心。
  • 單參數限制破解:Mapper 方法只能有一個參數,但可傳入 包裝類 POJO(如 `QueryVo` 包含 User + 分頁參數),滿足複雜查詢需求。注意:Service 層不建議用包裝類型,保持業務接口清晰。
  • ${} vs #{}: `${}` 是字符串拼接,用於表名、列名、排序字段等動態 SQL 結構,有 SQL 注入風險;`#{}` 是預編譯佔位符,用於業務參數,安全高效。
  • 映射文件註冊:別忘了在 `SqlMapConfig.xml` 中 `` 加載映射文件。

總結

Mapper 動態代理模式實現了 接口與實現分離、SQL 與代碼分離、參數結果類型安全,極大提升開發效率與可維護性。新項目請直接使用 Mapper 模式,拒絕原始 DAO 的樣板代碼地獄。

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