MyBatis 是一款優秀的持久層框架,支援自訂 SQL、預存程序以及進階映射。相較於 Hibernate 的全自動 ORM 映射,MyBatis 採用半自動方式,雖然需要手寫 SQL,但擁有極高的靈活度與效能優化空間,非常適合新手入門,學習門檻相對較低。
筆者早期使用 Hibernate,深愛其 POJO 註解映射與 HQL 查詢的便利性——get(id)、save(entity)、delete(entity)、update(entity) 幾行代碼即可完成 CRUD。然而隨著專案規模增長,資料庫效能問題頻現,必須深入優化 SQL 時,Hibernate 的黑盒機制反而成為阻礙。
MyBatis 雖需手寫 SQL,但字段映射機制完善,寫 SQL 的過程反而能加深對資料庫的理解,掌握索引設計、執行計劃分析等核心技能。選型建議:大型專案、高併發、複雜查詢優先 MyBatis;中小型後台管理系統、查詢量不大者 Hibernate 仍具生產力優勢。當然,全專案統一使用 MyBatis 也是許多團隊的標準做法。

本範例未使用 Maven 管理依賴(後續 SSM 整合篇將引入),核心 JAR 包清單如下:
此文件是 MyBatis 與資料庫的橋樑,包含資料源、事務管理器、Mapper 映射註冊等核心配置:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 整合 Spring 後 environments 配置將廢除 --> <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/mybatis?characterEncoding=utf-8" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> <!-- 配置 mapper 映射文件 --> <mappers> <mapper resource="sqlmap/User.xml"/> </mappers> </configuration>
針對 User 實體的 SQL 定義,展示基本 CRUD 與參數映射細節:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace 命名空間:使用 Mapper 動態代理時需配置為 Mapper 接口全限定名 -->
<mapper namespace="test">
<!-- 根據 ID 查詢單條記錄 -->
<select id="findUserById" parameterType="int" resultType="com.mybatis001.bean.User">
SELECT * FROM USER WHERE id = #{id}
</select>
<!-- 模糊查詢用戶列表 -->
<select id="findUserList" parameterType="java.lang.String" resultType="com.mybatis001.bean.User">
select * from user where name like '%${value}%'
</select>
<!-- 新增用戶,回填自增主鍵 -->
<insert id="insertUser" parameterType="com.mybatis001.bean.User">
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user(name,age,sex) values(#{name},#{age},#{sex})
</insert>
<!-- 刪除用戶 -->
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
</delete>
<!-- 更新用戶 -->
<update id="updateUser" parameterType="com.mybatis001.bean.User">
update user set name=#{name},age=#{age},sex=#{sex} where id=#{id}
</update>
</mapper>
關鍵點解析:
#{}:預編譯佔位符,防止 SQL 注入,參數名可任意${}:字串拼接,無法防注入,動態表名、排序欄位等場景必須使用<selectKey>:插入後回填自增主鍵到實體對象parameterType/resultType:輸入輸出類型映射,屬性名與查詢欄位名一致才能自動映射User.java - 標準 POJO,包含 id、name、age、sex 四個屬性及 Getter/Setter
UserDao.java - 定義資料訪問接口:
public interface UserDao {
User findUserById(int id) throws Exception;
List<User> findUserList(String name) throws Exception;
Integer insertUser(User user) throws Exception;
void deleteUser(int id) throws Exception;
void updateUser(User user) throws Exception;
}
UserDaoImpl.java - 基於 SqlSessionFactory 的原生實作:
public class UserDaoImpl implements UserDao {
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// statement 格式:namespace.id
User user = sqlSession.selectOne("test.findUserById", id);
sqlSession.close();
return user;
}
@Override
public List<User> findUserList(String name) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
List<User> userList = sqlSession.selectList("test.findUserList", name);
sqlSession.close();
return userList;
}
@Override
public Integer insertUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
int lastUserId = sqlSession.insert("test.insertUser", user);
sqlSession.commit();
sqlSession.close();
return lastUserId;
}
@Override
public void deleteUser(int id) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("test.deleteUser", id);
sqlSession.commit();
sqlSession.close();
}
@Override
public void updateUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.update("test.updateUser", user);
sqlSession.commit();
sqlSession.close();
}
}
public class UserDaoImplTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception {
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
User user = userDao.findUserById(1001);
List<User> userList = userDao.findUserList("lee");
userList.forEach(System.out::println);
}
@Test
public void insertUser() throws Exception {
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
userDao.insertUser(new User("nathan.lee.salvatore", 18, "男"));
userDao.insertUser(new User("nathan", 22, "男"));
userDao.insertUser(new User("leechenxiang", 20, "男"));
userDao.insertUser(new User("李晨翔", 19, "男"));
}
@Test
public void deleteUser() throws Exception {
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
userDao.deleteUser(1013);
}
@Test
public void updateUser() throws Exception {
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
User user = new User("李斯涵", 1, "女");
user.setId(1001);
userDao.updateUser(user);
}
}
完整代碼已上傳 GitHub:https://github.com/leechenxiang/mybatis001
下一篇將深入探討 MyBatis 動態 SQL、類型別名、Mapper 掃描等進階特性,敬請期待。