# MyBatis教程 - 9 使用注解开发

MyBatis 提供了注解开发的方式,可以让开发者不依赖 XxxMapper.xml 配置文件,直接在 XxxMapper.java 接口上使用注解来编写 SQL 语句。

但是对于复杂的 SQL 语句,使用注解的方式不易处理,所以针对简单的 SQL,可以使用注解的开发方式,而对于复杂的 SQL 还是建议使用 XxxMapper.xml 的 SQL 映射文件来完成。

# 9.1 注解方式实现增删改查

下面使用注解的开发方式,实现 User 表的增删改查,对于简单的 SQL,使用注解的方式还是非常方便的。

# 1 定义Mapper接口

还是在 UserMapper.java 中定义增删改查的相关接口,并在接口上使用注解定义 SQL 语句。

UserMapper.java :

package com.foooor.mybatis.mapper;

import com.foooor.mybatis.pojo.User;
import org.apache.ibatis.annotations.*;

public interface UserMapper {

    /**
     * 根据id查询用户信息
     */
    @Select("SELECT * FROM tb_user WHERE id = #{id}")
    User selectById(@Param("id") int id);

    /**
     * 插入用户信息
     */
    @Insert("INSERT INTO tb_user(username, password, email, age, create_time, update_time) VALUES (#{username}, #{password}, #{email}, #{age}, #{createTime}, #{updateTime})")
    @Options(useGeneratedKeys = true, keyProperty = "id") 
    int insert(User user);

    /**
     * 更新用户信息
     */
    @Update("UPDATE tb_user SET username = #{username}, password = #{password}, email = #{email}, age = #{age}, update_time = #{updateTime} WHERE id = #{id}")
    int update(User user);

    /**
     * 根据id删除用户信息
     */
    @Delete("DELETE FROM tb_user WHERE id = #{id}")
    int deleteById(@Param("id") int id);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

不用使用 UserMapper.xml 映射文件了,直接就可以测试了。

当然,我们可以同时使用注解和 XxxMapper.xml 进行混合开发,但是不能给一个接口同时添加注解和在 XxxMapper.xml 文件中进行 SQL 映射,会报错!

# 2 使用注解开发的优缺点

  • 优点
    • 简洁:使用注解避免了冗长的 XML 配置,直接将 SQL 语句放在接口上,代码更加简洁。
    • 易维护:SQL 语句和代码在一起,便于查看和修改。
  • 缺点
    • 复杂 SQL 不易处理:当 SQL 语句变得非常复杂时,注解会显得力不从心。此时,还是需要回到 XML 配置中编写复杂的 SQL 语句。
    • 可读性:对于非常长的 SQL 语句,直接写在注解中会导致代码可读性下降。

# 9.2 @Results和@Result注解

当查询数据库的字段名称和 Java 实体类中的属性名称不对应的时候,可以使用 @Results@Result 注解。

@Results 注解是用来定义一组 @Result 的容器,用于指定 SQL 查询结果与实体类属性的映射规则。

举个栗子:

当数据库的字段是 email,Java 实体类中的属性名称为 mailBox 时,可以使用下面的方式进行映射。

/**
 * 根据id查询用户信息
 */
@Select("SELECT * FROM tb_user WHERE id = #{id}")
@Results({
        @Result(property = "id", column = "id", id = true),
        @Result(property = "username", column = "username"),  // 这个可以省略,自动映射
        @Result(property = "mailBox", column = "email")
})
User selectById(@Param("id") int id);
1
2
3
4
5
6
7
8
9
10

在处理的时候,当名称不匹配的时候,使用 @Result 进行映射,如果名称是匹配的,MyBatis 会自动处理映射,无需使用 @Result 注解。所以上面的 username 是可以省略的。id 建议添加,标识主键。


还可以进行级联映射:

/**
 * 根据id查询学生信息
 */
@Select("SELECT stu.id as sid, stu.name as sname, stu.age, cla.id as cid, cla.name as cname, cla.student_count " +
        "FROM tb_student as stu LEFT JOIN tb_cla55 as cla ON stu.cla55_id = cla.id " +
        "WHERE stu.id = #{id}")
@Results({
        @Result(property = "id", column = "sid", id = true),
        @Result(property = "name", column = "sname"),
        @Result(property = "age", column = "age"),
        @Result(property = "cla55.id", column = "cid"),
        @Result(property = "cla55.name", column = "cname"),
        @Result(property = "cla55.studentCount", column = "student_count")
})
Student selectStuAndClassById(@Param("id") Integer id);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 9.3 多对一和一对多映射

使用注解也可以进行多对一和一对多的关系映射。

# 1 多对一映射

@Result 注解中有 one 属性,使用 one 属性可以进行多对一的关系映射。

举个栗子:

StudentMapper.java

/**
 * 根据id查询学生信息
 */
@Select("SELECT * FROM tb_student WHERE id = #{id}")
@Results({
        @Result(property = "id", column = "id", id = true),
        @Result(property = "name", column = "name"),  // 名称匹配,可以省略
        @Result(property = "cla55", column = "cla55_id", one = @One(select = "com.foooor.mybatis.mapper.Cla55Mapper.selectById", fetchType = FetchType.EAGER))
})
Student selectStuAndClassById(@Param("id") Integer id);
1
2
3
4
5
6
7
8
9
10

映射的时候,指定映射的属性和数据库字段,并指定查询关联的对象属性的 Mapper 方法。

# 2 一对多映射

@Result 注解中有 many 属性,使用 many 属性可以进行一对多的关系映射。

举个栗子:

Cla55Mapper.java

/**
 * 根据id查询班级和学生信息
 */
@Select("SELECT * FROM tb_cla55 WHERE id = #{id}")
@Results({
        @Result(column = "id", property = "id", id = true),
        @Result(column = "name", property = "name"),
        @Result(column = "studentCount", property = "studentCount"),
        @Result(column = "id", property = "studentList", many = @Many(select = "com.foooor.mybatis.mapper.StudentMapper.selectByCla55Id", fetchType = FetchType.EAGER))
})
Cla55 selectClassAndStuById(@Param("id") Integer id);
1
2
3
4
5
6
7
8
9
10
11