常用注解

MyBatis 是一款优秀的持久层框架,它支持通过注解的方式进行开发,而无需使用传统的 XML 配置文件。这种方式更加简洁、直观,适合于简单的应用场景或轻量级开发项目。

常用注解:

  • Insert - 新增
  • Update - 更新
  • Delete - 删除
  • Select - 查询
  • Result - 结果集封装
  • Results - 与 Result 一起使用,封装多个结果集
  • One - 实现一对一的结果封装
  • Many - 实现一对多的结果封装

Select

用途:用于执行查询操作。 位置:放在 Mapper 接口的方法上。 支持功能:可以直接写简单的查询语句,支持动态参数。

Insert

用途:用于执行插入操作。 位置:放在 Mapper 接口的方法上。 支持功能:支持插入单条记录或批量插入,支持自动生成主键。

Update

用途:用于执行更新操作。 位置:放在 Mapper 接口的方法上。 支持功能:支持根据条件更新记录。

Delete

用途:用于执行删除操作。 位置:放在 Mapper 接口的方法上。 支持功能:支持根据条件删除记录。

Results 和 Result

用途:用于结果集的手动映射,将查询的字段与对象属性一一对应。 位置:放在 Mapper 接口的方法上。 支持功能:用于字段名和对象属性名不一致的情况。

Param

用途:用于给 SQL 中的参数命名,绑定方法的参数到 SQL 语句中的占位符。 位置:放在 Mapper 方法的参数上。 支持功能:解决方法参数无法直接被引用或多参数的绑定问题。

Options

用途:用于设置方法的额外选项,比如主键生成、查询的缓存等。 位置:放在 @Insert、@Update 等注解上。

ResultMap

用途:引用 XML 或注解中定义的结果映射。 位置:放在 Mapper 接口的方法上。 支持功能:简化复杂的结果映射。

ConstructorArgs 和 Arg

用途:用于在构造函数映射场景中,将查询结果映射到构造函数参数。 位置:放在 Mapper 接口的方法上。

注解优点

  • 简洁:直接在代码中定义 SQL,无需额外的 XML 文件。
  • 强类型支持:与 Java 代码紧密结合,便于重构和代码检查。
  • 便于维护:SQL 紧贴业务逻辑,便于定位问题。

注解缺点

  • 不适合复杂 SQL:对于动态 SQL 和大段查询,注解方式不够灵活。
  • 代码冗长:复杂查询可能导致注解内容过多,影响可读性。
  • SQL 可重用性差:注解中的 SQL 不能像 XML 一样被复用。

常见使用

  • 简单 SQL 使用注解,复杂 SQL 使用 XML 配置文件。
  • 使用 @Param 命名参数,避免歧义。
  • 对大段复杂 SQL 优先采用 XML 的 <if><where> 标签,提高复用性。
  • 结合 SpringBoot 使用 @MapperScan 注解统一管理 Mapper。

注解映射

实现复杂关系映射之前我们可以在映射文件中通过配置来实现,使用注解开发后,我们可以使用 Results 注解,Result 注解,One 注解,Many 注解结合起来完成复杂功能的开发。

一对一

查询模型

用户表和订单表的关系,一个用户有多个订单,一个订单只从属于一个用户,一对一查询的需求是,查询一个订单,与此同时查询出该订单所属的用户。

编写代码

OrderMapper

新增了一个方法 findAllWithAnnotation,通过注解的方式进行开发:

@Select("select * from wzk_orders")
@Results({
        @Result(id = true, property = "id", column = "id"),
        @Result(property = "ordertime", column = "ordertime"),
        @Result(property = "total", column = "total"),
        @Result(
                property = "user", column = "uid",
                javaType = WzkUser.class,
                one = @One(select = "icu.wzk.mapper.UserMapper.findByIdWithAnnotation")
        ),
})
List<WzkOrder> findAllWithAnnotation();

UserMapper

在该类中再加入一个新的方法,也用注解的方式,因为 OrderMapper 中要用到:

@Select("select * from wzk_user where id = #{id}")
WzkUser findByIdWithAnnotation(int id);

调用代码

package icu.wzk;

import icu.wzk.mapper.OrderMapper;
import icu.wzk.mapper.UserMapper;
import icu.wzk.model.WzkOrder;
import icu.wzk.model.WzkUser;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class WzkIcu11 {
    public static void main(String[] args) throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                .build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
        List<WzkOrder> dataList = orderMapper.findAllWithAnnotation();
        dataList.forEach(System.out::println);
        sqlSession.close();
    }
}

测试结果

执行代码,对应的控制台输出结果如下所示:

WzkOrder(id=1, ordertime=Mon Nov 11 00:00:00 CST 2024, total=100.0, user=WzkUser(id=1, username=wzk, password=icu, birthday=Mon Nov 11 00:00:00 CST 2024, orderList=null, roleList=null))
WzkOrder(id=2, ordertime=Mon Nov 11 00:00:00 CST 2024, total=200.0, user=WzkUser(id=1, username=wzk, password=icu, birthday=Mon Nov 11 00:00:00 CST 2024, orderList=null, roleList=null))
WzkOrder(id=3, ordertime=Sun Nov 10 00:00:00 CST 2024, total=150.0, user=WzkUser(id=2, username=wzk2, password=icu2, birthday=Mon Nov 11 00:00:00 CST 2024, orderList=null, roleList=null))