第06章 Mapper接口 - MyBatis学习教程

第06章 Mapper接口

掌握 Mapper 接口的使用和接口映射机制

学习进度:24%

💻 查看完整代码 - 在线IDE体验

🎯 学习目标

📚

理解核心概念

掌握本章的核心概念和基本原理

🔧

掌握实践技能

学会相关的配置方法和实践技巧

💡

了解应用场景

明确在实际项目中的应用场景和最佳实践

学习目标

深入理解MyBatis Mapper接口的概念和作用

掌握XML映射和注解映射两种方式

了解Mapper代理机制的工作原理

学会定义和使用各种Mapper方法

掌握参数传递和结果处理的技巧

Mapper接口概述

Mapper接口是MyBatis的核心组件,它定义了数据访问的方法签名,MyBatis会自动为这些接口创建代理实现,将方法调用转换为SQL执行。

Mapper接口的优势

类型安全:编译时检查方法签名和参数类型

代码简洁:无需编写实现类,只需定义接口

易于维护:接口与SQL映射分离,便于管理

IDE支持:完整的代码提示和重构支持

XML映射方式

1. 定义Mapper接口

package com.example.mybatis.mapper;

import com.example.mybatis.model.User;

import org.apache.ibatis.annotations.Param;

import java.util.List;

import java.util.Map;

public interface UserMapper {

// 查询所有用户

List selectAllUsers();

// 根据ID查询用户

User selectUserById(Long id);

// 根据年龄查询用户

List selectUsersByAge(@Param("age") Integer age);

// 条件查询

List selectUsersByCondition(Map params);

// 统计用户数量

long countUsers();

// 插入用户

int insertUser(User user);

// 更新用户

int updateUser(User user);

// 删除用户

int deleteUser(Long id);

}

2. 创建XML映射文件

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

useGeneratedKeys="true" keyProperty="id">

INSERT INTO users (name, age, email)

VALUES (#{name}, #{age}, #{email})

UPDATE users SET name = #{name}, age = #{age}, email = #{email}

WHERE id = #{id}

DELETE FROM users WHERE id = #{id}

3. 配置映射文件

注解映射方式

1. 基本注解

@Mapper

public interface UserAnnotationMapper {

@Select("SELECT id, name, age, email FROM users")

List findAllUsers();

@Select("SELECT id, name, age, email FROM users WHERE id = #{id}")

User findUserById(@Param("id") Long id);

@Insert("INSERT INTO users(name, age, email) VALUES(#{name}, #{age}, #{email})")

@Options(useGeneratedKeys = true, keyProperty = "id")

int insertUser(User user);

@Update("UPDATE users SET name = #{name}, age = #{age}, email = #{email} WHERE id = #{id}")

int updateUser(User user);

@Delete("DELETE FROM users WHERE id = #{id}")

int deleteUser(@Param("id") Long id);

@Select("SELECT COUNT(*) FROM users")

long countUsers();

}

2. 结果映射注解

@Select("SELECT id, name, age, email FROM users")

@Results({

@Result(property = "id", column = "id"),

@Result(property = "name", column = "name"),

@Result(property = "age", column = "age"),

@Result(property = "email", column = "email")

})

List findAllUsersWithMapping();

3. 动态SQL注解

@SelectProvider(type = UserSqlProvider.class, method = "selectUsersByCondition")

List findUsersByCondition(@Param("name") String name, @Param("minAge") Integer minAge);

// SQL提供者类

class UserSqlProvider {

public String selectUsersByCondition(@Param("name") String name, @Param("minAge") Integer minAge) {

StringBuilder sql = new StringBuilder("SELECT id, name, age, email FROM users WHERE 1=1");

if (name != null && !name.isEmpty()) {

sql.append(" AND name LIKE CONCAT('%', #{name}, '%')");

}

if (minAge != null) {

sql.append(" AND age >= #{minAge}");

}

return sql.toString();

}

}

Mapper代理机制

1. 代理对象的创建

// MyBatis自动创建代理对象

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

// 查看代理对象信息

System.out.println("Mapper接口类型: " + userMapper.getClass().getName());

System.out.println("是否为代理对象: " + userMapper.getClass().getName().contains("Proxy"));

2. 方法调用流程

调用Mapper接口方法

代理对象拦截方法调用

根据方法名查找对应的SQL语句

执行SQL并处理结果

返回处理后的结果

参数传递

1. 单个参数

// 接口定义

User selectUserById(Long id);

// XML映射

2. 多个参数(使用@Param)

// 接口定义

List selectUsersByAgeRange(@Param("minAge") Integer minAge,

@Param("maxAge") Integer maxAge);

// XML映射

3. 对象参数

// 接口定义

int insertUser(User user);

// XML映射

INSERT INTO users (name, age, email)

VALUES (#{name}, #{age}, #{email})

4. Map参数

// 接口定义

List selectUsersByCondition(Map params);

// XML映射

返回值处理

1. 基本类型返回值

// 返回数量

long countUsers();

// 返回影响行数

int insertUser(User user);

int updateUser(User user);

int deleteUser(Long id);

2. 对象返回值

// 返回单个对象

User selectUserById(Long id);

// 返回对象列表

List selectAllUsers();

3. Map返回值

// 返回Map

@MapKey("id")

Map selectUsersAsMap();

// 返回单行Map

Map selectUserAsMap(Long id);

最佳实践

1. 接口设计原则

方法名要清晰表达业务意图

参数类型要明确,避免使用Object

返回值类型要准确,避免过度包装

合理使用@Param注解标识参数

2. XML vs 注解选择

简单SQL:使用注解,代码更简洁

复杂SQL:使用XML,可读性更好

动态SQL:推荐使用XML

团队规范:保持一致的风格

3. 性能优化

合理设计方法签名,避免不必要的数据传输

使用合适的返回值类型

避免在Mapper中进行复杂的业务逻辑

合理使用批量操作方法

常见问题与解决方案

Q: Mapper接口方法找不到对应的SQL语句?

A: 检查namespace是否正确,方法名是否与SQL语句的id一致。

Q: 多个参数时出现参数绑定错误?

A: 使用@Param注解明确指定参数名称。

Q: 如何处理返回null的情况?

A: 在业务层进行null检查,或者使用Optional包装返回值。

Q: 注解和XML映射可以混合使用吗?

A: 可以,但建议在同一个项目中保持一致的风格。

实践练习

练习1:基本Mapper接口

创建一个完整的UserMapper接口,包含CRUD操作和统计方法。

练习2:注解映射

使用注解方式重新实现UserMapper的部分方法。

练习3:复杂参数传递

实现一个支持多条件查询的方法,使用Map传递参数。

练习4:批量操作

实现批量插入和批量删除的Mapper方法。

运行示例程序

步骤1:导入项目

将chapter-06-mapper-interface.json导入到IntelliJ IDEA中。

步骤2:配置数据库

确保MySQL数据库运行正常,执行init.sql创建测试数据。

步骤3:运行程序

运行MapperInterfaceDemo.java,观察不同映射方式的执行效果。

步骤4:查看结果

程序将演示XML映射器、注解映射器、Mapper方法和代理机制的使用。

挠脚心动画
一名足球评论员眼中的苏超:球迷嘉年华媲美国际大赛,苏超给中国足球诸多启示