MyBatis 注解Annotation实现CRUD操作全解析
作者:chxii
MyBatis 提供了 注解(Annotation) 方式来实现 CRUD 操作,适用于简单、轻量级的数据库交互场景。相比 XML 配置,注解方式将 SQL 直接写在 Mapper 接口方法上,代码更紧凑,开发效率更高。
一、MyBatis 注解 CRUD 核心注解
| 注解 | 作用 | 说明 |
|---|---|---|
@Select | 查询 | 对应 SELECT 语句 |
@Insert | 插入 | 对应 INSERT 语句 |
@Update | 更新 | 对应 UPDATE 语句 |
@Delete | 删除 | 对应 DELETE 语句 |
@Param | 参数绑定 | 多参数时指定参数名 |
@Options | 配置选项 | 如主键回填、缓存等 |
@Results / @Result | 结果映射 | 替代 <resultMap> |
@SelectProvider 等 | 动态 SQL(高级) | 通过类方法生成 SQL(较少用) |
⚠️ 注意:MyBatis 注解 不支持
<if>、<foreach>等动态标签,复杂逻辑仍需 XML。
二、准备工作
1. 实体类(User.java)
public class User {
private Long id;
private String name;
private String email;
// 构造函数、getter/setter 略
}2. 数据库表(MySQL 示例)
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100)
);三、注解实现 CRUD 完整示例
Mapper 接口:UserMapper.java
import org.apache.ibatis.annotations.*;
import java.util.List;
public interface UserMapper {
// 1. 新增(INSERT)
@Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
int insert(User user);
// 2. 根据 ID 查询(SELECT)
@Select("SELECT * FROM users WHERE id = #{id}")
User selectById(@Param("id") Long id);
// 3. 查询所有
@Select("SELECT * FROM users")
List<User> selectAll();
// 4. 更新(UPDATE)
@Update("UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}")
int update(User user);
// 5. 删除(DELETE)
@Delete("DELETE FROM users WHERE id = #{id}")
int deleteById(@Param("id") Long id);
// 6. 带条件查询(多参数)
@Select("SELECT * FROM users WHERE name LIKE CONCAT('%', #{name}, '%') AND email = #{email}")
List<User> findByNameAndEmail(@Param("name") String name, @Param("email") String email);
}四、关键细节详解
1. 主键自增回填(@Options)
@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
useGeneratedKeys = true:启用 JDBC 获取自增主键;keyProperty = "id":将生成的主键值赋给 User 对象的id字段;keyColumn = "id":数据库主键列名(通常可省略,MyBatis 自动推断)。
✅ 插入后,
user.getId()即可获得数据库生成的 ID。
2. 多参数传递(@Param)
当方法有多个参数时,必须使用 @Param 指定名称:
@Select("SELECT * FROM users WHERE name = #{name} AND email = #{email}")
User findByTwoParams(@Param("name") String name, @Param("email") String email);否则 MyBatis 无法识别 #{name} 对应哪个参数。
3. 字段映射(@Results)
如果数据库字段与 Java 属性名不一致(如 user_name vs userName),可用 @Results 显式映射:
@Select("SELECT user_id, user_name, user_email FROM users WHERE user_id = #{id}")
@Results({
@Result(property = "id", column = "user_id"),
@Result(property = "name", column = "user_name"),
@Result(property = "email", column = "user_email")
})
User selectByIdWithMapping(@Param("id") Long id);💡 若开启 mapUnderscoreToCamelCase,则无需手动映射。
五、测试示例(JUnit + MyBatis)
@Test
public void testCrud() throws IOException {
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// 插入
User user = new User();
user.setName("王五");
user.setEmail("wangwu@example.com");
mapper.insert(user); // 此时 user.id 已被填充
System.out.println("插入ID: " + user.getId());
// 查询
User found = mapper.selectById(user.getId());
System.out.println("查询结果: " + found.getName());
// 更新
found.setEmail("new_wangwu@example.com");
mapper.update(found);
// 删除
mapper.deleteById(found.getId());
session.commit(); // 注意:DML 操作需提交事务
}
}⚠️ 重要:MyBatis 默认不自动提交事务!执行 INSERT/UPDATE/DELETE 后需调用
session.commit(),或配置autoCommit=true(不推荐生产环境使用)。
六、优点与局限性
✅ 优点
- 代码简洁:SQL 与接口方法紧耦合,无需额外 XML 文件;
- 开发快速:适合单表、静态 SQL 场景;
- 易于理解:CRUD 逻辑一目了然。
❌ 局限性
| 问题 | 说明 |
|---|---|
| 不支持动态 SQL | 无法使用 <if>、<choose>、<foreach> 等标签 |
| SQL 复杂度受限 | 多表 JOIN、嵌套查询难以维护 |
| 无法复用 SQL 片段 | 不能像 XML 那样用 <sql> 提取公共部分 |
| 可读性差(长 SQL) | SQL 写在字符串中,无语法高亮,易出错 |
| 调试困难 | SQL 错误只能运行时发现,IDE 无法校验 |
七、尽管注解方便,但在以下场景中,XML 映射文件是不可替代的:
1.动态 SQL 支持强大
MyBatis 的核心优势之一是 动态 SQL(如 <if>、<choose>、<foreach> 等),而注解中写动态 SQL 极其困难甚至不可读。
❌ 注解写动态 SQL(不推荐):
@Select("<script>" +
"SELECT * FROM users WHERE 1=1 " +
"<if test='name != null'> AND name LIKE CONCAT('%', #{name}, '%') </if>" +
"<if test='email != null'> AND email = #{email} </if>" +
"</script>")
List<User> findUsers(@Param("name") String name, @Param("email") String email);- 字符串拼接易出错;
- 无法格式化,难以维护;
- 不支持 IDE 语法高亮和校验。
✅ XML 写法(清晰优雅):
<select id="findUsers" resultType="User">
SELECT * FROM users
<where>
<if test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="email != null">
AND email = #{email}
</if>
</where>
</select>📌 结论:只要涉及条件组合、分页、批量操作等,XML 是唯一合理选择。
2.复杂结果映射(ResultMap)
当实体类与数据库字段命名不一致,或存在一对一/一对多关联查询时,需使用 <resultMap>。
示例:用户 + 角色关联
<resultMap id="UserWithRoles" type="User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<collection property="roles" ofType="Role">
<id property="id" column="role_id"/>
<result property="name" column="role_name"/>
</collection>
</resultMap>
<select id="selectUserWithRoles" resultMap="UserWithRoles">
SELECT u.id AS user_id, u.name AS user_name,
r.id AS role_id, r.name AS role_name
FROM users u
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN roles r ON ur.role_id = r.id
WHERE u.id = #{id}
</select>❌ 注解无法优雅表达这种嵌套映射,只能通过
@Results手动配置,代码冗长且不支持集合映射。
3.SQL 复用与模块化
XML 支持 <sql> 片段复用:
<sql id="userColumns">id, name, email</sql>
<select id="selectAll" resultType="User">
SELECT <include refid="userColumns"/> FROM users
</select>注解无法实现 SQL 片段提取,导致重复代码。
4.可维护性与团队协作
- XML 文件可被 DBA 审查、优化;
- SQL 与 Java 代码分离,符合“关注点分离”原则;
- 更容易做 SQL 性能调优、日志追踪;
- 支持 MyBatis Generator 自动生成 XML 和实体类。
5.特殊 SQL 语法兼容性更好
某些数据库特有语法(如 Oracle 的 MERGE、PostgreSQL 的 JSON 操作)在 XML 中更易书写和调试。
八、总结
| 功能 | 注解实现 | 是否推荐 |
|---|---|---|
| 单表 INSERT/UPDATE/DELETE | ✅ 支持 | ✅ 简单场景推荐 |
| 单条件 SELECT | ✅ 支持 | ✅ |
| 多条件动态查询 | ❌ 不支持(需拼字符串) | ❌ 不推荐 |
| 关联查询(JOIN) | ⚠️ 可写但难维护 | ❌ 不推荐 |
| 主键回填 | ✅ 支持(@Options) | ✅ |
| 字段映射 | ✅ 支持(@Results) | ⚠️ 开启驼峰更佳 |
🔔 结论:
MyBatis 注解是 轻量级 CRUD 的利器,但 不是万能方案。
在快速开发、脚本工具、微服务 DAO 层等场景下非常高效;
但在企业级应用中,XML 仍是主力,注解仅作补充。注解是“糖”,XML 是“饭”。
糖可以提味,但不能当饭吃。在真实业务系统中,XML 的灵活性、可读性和功能完整性使其具有不可替代的地位。
到此这篇关于MyBatis 注解Annotation实现CRUD操作全解析的文章就介绍到这了,更多相关MyBatis 注解实现CRUD内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
