接口类

一、@Mapper 与 @MapperScan

  1. 是 Mybatis 和 Spring/Spring Boot 整合的核心注解,让 Mybatis 识别项目中的 Mapper 接口,为其动态生成代理实现类,并将代理对象注册到 IOC 容器中,使 Mapper 接口通过 @Autowired 注入使用

  2. @Mapper :标注在单个 Mapper 接口

  3. 局部生效:仅对标注了该注解的 Mapper 接口有效

  4. 适合少量 Mapper 接口,无需配置扫描路径,直接标注

  5. 无需额外配置,自动完成代理 Bean 的注册

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import cn.wolfcode.mapper.UserMapper;
import cn.wolfcode.domain.User;

@Service
public class UserService {
    // 注入MyBatis生成的UserMapper代理对象(单例)
    @Autowired
    private UserMapper userMapper;

    public User getUser(Long id) {
        // 实际调用的是代理对象的方法,执行数据库查询
        return userMapper.selectById(id);
    }
}
  1. @MapperScan:通常标注在 Spring Boot 主启动类上

  2. 通过basePackages9(或 value)指定 Mapper 接口所在包路径

  3. 全局配置:一次配置,自动扫描该包下的所有 Mapper 接口

  4. 管理集中:Mapper 扫描同一配置在主启动器,便于维护

二、Mybatis 核心 CRUD 注解

  1. Mybatis 提供了与 SQL 操作对应的基础注解,替代传统 XML 映射文件,直接在 Mapper 接口方法上声明 SQL 语句

  2. @Select :映射查询 SQL

  3. @Insert:映射插入 SQL;配合@Options 实现主键自增

  4. @Update:映射更新;

  5. @Delete:映射单条删除 SQL

    @Select("select * from employee")
    @Results({
            //标记当前映射的字段为实体类的主键字段(等价于 XML 中的<id/>标签)。
            @Result(column = "id", property = "id", id = true),
            @Result(column = "name", property = "name"),
            @Result(column = "sal", property = "sal"),
            @Result(column = "sex", property = "sex"),
    })
    List<Employee> selectAll();

    @Insert("insert into employee(name, sal, sex) values(#{name}, #{sal}, #{sex})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(Employee employee);

    @Update("update employee set name=#{name}, sal=#{sal}, sex=#{sex} where id=#{id}")
    int update(Employee employee);
    
    @Delete("delete from employee where id=#{id}")
    int deleteById(Long id);
  1. #{xxx} :注解中的都是 MyBatis 的预编译参数占位符

  2. 自动完成 Java 类型与数据库类型的转换(如 String → VARCHAR、Long → BIGINT)

  3. 有效防止 SQL 注入

  4. 无需手动拼接参数

区别于 ${},字符串直接替换,有 SQL 注入风险

三、结果映射注解:@Results + @Result

  1. 核心作用:解决数据库表列名与 Java 实体类属性名的映射关系,等价于 XML 映射文件中的 标签

  2. 注解属性

@Results({
    // 标记主键字段,id = true 等价于 XML 中的 <id/> 标签,MyBatis 会做主键优化
    @Result(column = "id", property = "id", id = true),
    // 普通字段映射:column=数据库列名,property=实体类属性名
    @Result(column = "name", property = "name"),
    @Result(column = "sal", property = "sal"),
    @Result(column = "sex", property = "sex"),
})
  1. column:数据库表列名

  2. property:Java 实体类的属性名

  3. id = true:标记当前字段为主键字段,Mybatis 会对主键做缓存优化,提升查询效率

  4. 复用结果映射:@ResultMap 代替重复的 @Results

定义全局结果映射,其他方法直接引用

// 1. 定义全局结果映射,指定id(唯一标识)
@Results(id = "employeeResultMap", value = {
    @Result(column = "id", property = "id", id = true),
    @Result(column = "name", property = "name"),
    @Result(column = "sal", property = "sal"),
    @Result(column = "sex", property = "sex"),
})
List<Employee> selectAll();

// 2. 其他方法直接用@ResultMap引用,无需重复定义
@Select("select * from employee where id=#{id}")
@ResultMap("employeeResultMap")
Employee findById(Long id);

四、主键自增:@Options 注解

  1. 在 insert 方法中,@Options(useGeneratedKeys = true, keyProperty = "id") 是新增数据后获取数据库自增主键的核心配置

    @Insert("insert into employee(name, sal, sex) values(#{name}, #{sal}, #{sex})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(Employee employee);
  1. 注解属性:

  2. useGeneratedKeys = true:告诉 Mybatis 启用自增主键获取功能

  3. keyProperty = "id":将数据库生成的自增键值,赋值给实体对象的 id 属性上

五、动态 SQL:@XXXProvider

  1. Provider 系列注解,通过 Java 代码动态构建 SQL 语句,替代 XML 中的 <if><foreach><where> 等动态标签

  2. 核心属性:

  3. type:指定提供 SQL 语句的类

  4. method:指定 type 类中对应 SQL 的方法名(方法返回值必须为 String,即拼接好的字符串)

    @UpdateProvider(type = EmployeeMapper.SQLProvider.class, method = "update")
    int updatePatch(Employee employee);
    
    
    @DeleteProvider(type = EmployeeMapper.SQLProvider.class, method = "deleteByIds")
    int deleteByIds(Long[] ids);
    
    
    @SelectProvider(type = EmployeeMapper.SQLProvider.class, method = "selectByQO")
    @Results({
            @Result(column = "id", property = "id", id = true),
            @Result(column = "name", property = "name"),
            @Result(column = "sal", property = "sal"),
            @Result(column = "sex", property = "sex"),
    })
    List<Employee> selectByQO(EmployeeQO qo);

六、SQL 动态构建:SQLProvider 内部类

  1. SQLProvider 是 EmployeeMapper 的静态内部类(必须静态,否则 Mybatis 无法实例化),专门负责动态拼接

public interface EmployeeMapper {
    class SQLProvider {
    //动态 SQL 实现方法
    }
}    
  1. 动态更新

public String update(Employee employee) {
    StringBuffer sql = new StringBuffer("update employee set ");
    // 非空判断:只拼接属性非空的更新语句
    if (!StringUtils.isEmpty(employee.getName())) {
        sql.append("name=#{name},");
    }
    if (!StringUtils.isEmpty(employee.getSal())) {
        sql.append("sal=#{sal},");
    }
    if (!StringUtils.isEmpty(employee.getSex())) {
        sql.append("sex=#{sex},");
    }
    // 截取最后一个逗号(解决拼接后末尾多逗号的语法错误)
    String substring = sql.substring(0, sql.length() - 1);
    // 拼接where条件,按主键更新
    substring += " where id=#{id}";
    return substring;
}
  1. 批量删除

public String deleteByIds(Long[] ids) {
    StringBuffer sql = new StringBuffer("delete from employee where id in (");
    // 遍历id数组,拼接成 1,2,3 形式
    for (Long id : ids) {
        sql.append(id);
        // 最后一个id后不加逗号
        if (id != ids[ids.length - 1]) {
            sql.append(",");
        }
    }
    sql.append(")");
    return sql.toString();
}
  1. 多条件查询

使用 QO 封装多条件查询的参数,代替 Mapper 方法的多个零散参数

public String selectByQO(EmployeeQO qo) {
    // 经典写法:where 1=1,解决第一个条件前多and的语法问题
    StringBuffer sql = new StringBuffer("select * from employee where 1=1 ");
    // 姓名模糊查询:非空则拼接
    if (!StringUtils.isEmpty(qo.getName())) {
        sql.append("and name like #{name}");
    }
    // 薪资大于等于下限
    if (!StringUtils.isEmpty(qo.getStartSal())) {
        sql.append("and sal >= #{startSal}");
    }
    // 薪资小于等于上限
    if (!StringUtils.isEmpty(qo.getEndSal())) {
        sql.append("and sal <= #{endSal}");
    }
    return sql;
}

where 1=1 :保证即使没有任何查询条件,SQL 语句依然合法

七、PageHelper 分页

  1. 核心作用:替代手动拼接 LIMIT 分页 SQL,一行代码开启分页,自动拦截 Mybatis 查询并完成分页,同时封装分页结果

  2. 代码展示

@Test
void testSelectByPage() {
    EmployeeQO qo = new EmployeeQO(); // 1. 查询条件(此处无条件,查所有)
    PageHelper.startPage(1, 2);       // 2. 开启分页:参数(当前页码, 每页条数),页码从1开始
    List<Employee> list = employeeMapper.selectByQO(qo); // 3. 执行查询,PageHelper自动分页
    PageInfo<Employee> pageInfo = new PageInfo<>(list); // 封装分页信息
    List<Employee> currentPageData = pageInfo.getList(); // 获取当前页实际数据
    currentPageData.stream().forEach(System.out::println); // 打印分页结果
}
  1. 核心类、方法

  2. PageHelper.startPage(页号, 每页条数):分页开关,会自动紧跟下一个 MyBatis 查询生效

  3. PageInfo:分页结果封装类,传入查询结果后,通过 getList() 直接获取分页后的当前页数据,还能简单获取总条数 pageInfo.getTotal()、总页数pageInfo.getPages()

  4. 注意:PageHelper.startPage() 必须紧跟 MyBatis 查询方法,中间不能插其他 MyBatis 操作(如另一个 mapper 查询),否则分页会失效

八、注解开发 和 XML 开发

  1. 注解开发:代码集中在 Mapper 接口中、开发效率高、无需维护 XML ;动态 SQL 拼接繁琐,复杂 SQL 可读性差;适用:单表操作、简单动态 SQL 场景

  2. XML 开发:动态 SQL 标签(/)简洁、复杂 SQL 可读性高、易维护;需维护 XML 文件,代码分散;适用:多表联查、复杂动态 SQL 场景

posted @ 2026-01-31 11:48  北海道第一原神高手  阅读(0)  评论(0)    收藏  举报