MyBatis 作為優秀的持久層框架,提供了兩種 DAO 開發模式:原始 DAO 開發(手寫實現類)與 Mapper 動態代理開發(僅定義接口,框架自動生成實現)。實際項目中極力推薦 Mapper 模式,本文將對比兩者優劣、剖析核心原理、給出生產級最佳實踐。
| 對象 | 角色 | 最佳作用域 | 線程安全 | 說明 |
|---|---|---|---|---|
| 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 接口 + 實現類,實現類中注入 `SqlSessionFactory`,手動管理 `SqlSession` 生命周期,硬編碼 Statement ID。
僅定義 Mapper 接口,MyBatis 根據接口方法簽名自動生成 JDK 動態代理對象,內部委託 `SqlSession` 執行 SQL。
namespace = Mapper 接口全限定名<select|insert|update|delete> 的 idparameterTyperesultType / 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 動態代理模式實現了 接口與實現分離、SQL 與代碼分離、參數結果類型安全,極大提升開發效率與可維護性。新項目請直接使用 Mapper 模式,拒絕原始 DAO 的樣板代碼地獄。