【一文搞懂】MyBatis-Plus中核心类BaseMapper的基础和进阶用法


MyBatis-Plus 核心类 BaseMapper 主要提供基本的 CRUD(创建、读取、更新、删除)操作的接口定义。它可以大大简化基于 MyBatis 的数据访问层代码的编写。源码部分如下图所示:

在这里插入图片描述在这里插入图片描述

基础用法

可见BaseMapper 接口定义了一些基本的数据库操作方法,用法概览如下:

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;

public interface BaseMapper<T> extends Mapper<T> {
	// 插入一条记录
    int insert(T entity);
	// 根据主键删除记录
    int deleteById(Serializable id);
	// 根据columnMap条件,删除记录
    int deleteByMap(@Param("cm") Map<String, Object> columnMap);
	// 根据条件构造器删除记录
    int delete(@Param("ew") Wrapper<T> queryWrapper);
	// 根据ID列表批量删除
    int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
	// 根据ID更新记录(全部字段)
    int updateById(@Param("et") T entity);
	// 根据条件构造器更新记录
    int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
	// 根据ID查询记录
    T selectById(Serializable id);
	// 根据ID列表批量查询
    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
	// 根据columnMap条件查询记录
    List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
	// 根据条件构造器查询一条记录
    T selectOne(@Param("ew") Wrapper<T> queryWrapper);
	// 根据条件构造器查询记录数
    Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
	// 根据条件构造器查询记录列表
    List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
	// 根据条件构造器查询全部记录,将每条记录封装为一个Map对象,List<Map<String, Object>>形式。
    List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
	// 根据条件构造器查询全部记录,将每条记录封装为一个Object数组,List<Object[]> 形式。
    List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
	// 分页查询,返回实体类的分页结果
    <E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
	// 分页查询,返回的Map<String, Object>形式的分页结果
    <E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}

简单应用示例:
假设User 的实体类对应数据库中的用户表,其字段包括 id、username 和 password,则可以创建一个对应的 UserMapper 接口,继承自 BaseMapper 接口,从而获得基本的 CRUD 方法的实现。

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 这里不需要编写任何方法,继承了 BaseMapper 接口后,已经包含了常用的数据库操作方法
}

然后在服务层或控制器层中注入 UserMapper并调用其方法可实现数据库操作。

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    // 增加用户
    public void addUser(User user) {
        userMapper.insert(user);
    }

    // 根据用户ID查询
    public User getUserById(Long userId) {
        return userMapper.selectById(userId);
    }

    // 更新信息
    public void updateUser(User user) {
        userMapper.updateById(user);
    }

    // 删除用户
    public void deleteUser(Long userId) {
        userMapper.deleteById(userId);
    }
}

通过上述方式可以非常方便地进行数据库操作,而不需要编写繁琐的 SQL 语句。

进阶用法

自定义SQL语句

方式一:使用注解自定义SQL方法

假设我们有一个实体类 CourseBase 和对应的 Mapper 接口,我们希望添加一个查询功能,查询所有课程名称包含指定关键字的课程。

public interface CourseBaseMapper extends BaseMapper<CourseBase> {

    // 自定义 SQL 查询:根据名称模糊查询课程
    @Select("SELECT * FROM course_base WHERE name LIKE CONCAT('%', #{nameKeyword}, '%')")
    List<CourseBase> selectCoursesByName(@Param("nameKeyword") String nameKeyword);
}

方式二:使用XML文件自定义SQL方法

在 Mapper 接口中声明方法

public interface CourseBaseMapper extends BaseMapper<CourseBase> {
    List<CourseBase> selectCoursesByStatus(String status);
}

在 resources/mapper/ 目录下创建一个名为 CourseBaseMapper.xml 的文件。这个文件与 CourseBaseMapper 接口绑定。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.demo.mapper.CourseBaseMapper">
    <!-- 自定义 SQL 查询:根据状态查询课程 -->
    <select id="selectCoursesByStatus" resultType="com.example.demo.entity.CourseBase">
        SELECT * FROM course_base WHERE status = #{status}
    </select>
</mapper>

针对上述两种方式,在业务逻辑中则可调用这些自定义的方法

@Service
public class CourseService {

    @Autowired
    private CourseBaseMapper courseBaseMapper;

    public List<CourseBase> getCoursesByName(String nameKeyword) {
        return courseBaseMapper.selectCoursesByName(nameKeyword); // 使用注解方式的方法
    }

    public List<CourseBase> getCoursesByStatus(String status) {
        return courseBaseMapper.selectCoursesByStatus(status); // 使用 XML 方式的方法
    }
}

注解方式和XML比较:

  1. 注解
    优点:简单、清晰,适合处理较为简单的 SQL 查询。
    缺点:对于复杂查询,SQL 语句难以维护,可读性较差。
  2. XML
    优点:适合复杂查询,SQL 语句与 Java 代码分离,易于维护和调试。
    缺点:需要额外的 XML 文件,配置稍微麻烦一些。

条件构造器

MyBatis-Plus 的条件构造器(如 QueryWrapper、UpdateWrapper、LambdaQueryWrapper、LambdaUpdateWrapper 等)非常强大,可以帮助开发人员以链式编程的方式构建复杂的查询条件。

使用 QueryWrapper 进行查询

QueryWrapper 用于构建查询条件,例如多条件过滤、排序等。假设我们有一个 CourseBase 实体类和对应的 CourseBaseMapper 接口。

示例:查询课程名称包含 “Java” 并且状态为 “已发布” 的记录,按创建时间降序排序

@Service
public class CourseService {

    @Autowired
    private CourseBaseMapper courseBaseMapper;

    public List<CourseBase> getPublishedJavaCourses() {
        QueryWrapper<CourseBase> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name", "Java") // 查询课程名称包含 "Java"
                    .eq("status", "已发布") // 查询状态为 "已发布"
                    .orderByDesc("create_date"); // 按创建时间降序排序

        return courseBaseMapper.selectList(queryWrapper);
    }
}

使用 UpdateWrapper 进行更新

UpdateWrapper 用于构建更新操作的条件,可以根据指定的条件更新字段。

示例:将所有课程状态为 “未发布” 的课程状态更新为 “已发布”

@Service
public class CourseService {

    @Autowired
    private CourseBaseMapper courseBaseMapper;

    public int publishUnpublishedCourses() {
        UpdateWrapper<CourseBase> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("status", "未发布") // 条件:状态为 "未发布"
                     .set("status", "已发布"); // 更新状态为 "已发布"

        return courseBaseMapper.update(null, updateWrapper); // 执行更新操作
    }
}

使用 LambdaQueryWrapper 进行查询

LambdaQueryWrapper 是 QueryWrapper 的 lambda 表达式版本,它在属性引用上更安全(不会因为字段名拼写错误而出错),适合复杂查询。

示例:查询所有创建人是 “张三” 且课程等级为 “高级” 的记录

@Service
public class CourseService {

    @Autowired
    private CourseBaseMapper courseBaseMapper;

    public List<CourseBase> getAdvancedCoursesByCreator() {
        LambdaQueryWrapper<CourseBase> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(CourseBase::getCreatePeople, "张三") // 条件:创建人为 "张三"
                          .eq(CourseBase::getGrade, "高级"); // 条件:课程等级为 "高级"

        return courseBaseMapper.selectList(lambdaQueryWrapper);
    }
}

使用 LambdaUpdateWrapper 进行更新

LambdaUpdateWrapper 是 UpdateWrapper 的 lambda 表达式版本,用于构建更新操作的条件和更新字段,保证字段名的安全性。

示例:将所有适用人群为 “学生” 的课程标签更新为 “推荐”

@Service
public class CourseService {

    @Autowired
    private CourseBaseMapper courseBaseMapper;

    public int updateTagsForStudents() {
        LambdaUpdateWrapper<CourseBase> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(CourseBase::getUsers, "学生") // 条件:适用人群为 "学生"
                           .set(CourseBase::getTags, "推荐"); // 更新标签为 "推荐"

        return courseBaseMapper.update(null, lambdaUpdateWrapper);
    }
}

分页查询

假设现在实体类如下

@Data
@TableName("user")
public class User {
    @TableId
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

创建 UserMapper 接口,继承 BaseMapper

public interface UserMapper extends BaseMapper<User> {
}

创建 UserService 类,使用 UserMapper 进行分页查询

@Service
public class UserService extends ServiceImpl<UserMapper, User> {

    public Page<User> getUserPage(int pageNum, int pageSize) {
        Page<User> page = new Page<>(pageNum, pageSize); // 创建分页对象
        return this.baseMapper.selectPage(page, null); // 查询并返回分页结果
    }
}

在控制器中调用 UserService 进行分页查询

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/users")
    public Page<User> getUsers(@RequestParam int pageNum, @RequestParam int pageSize) {
        return userService.getUserPage(pageNum, pageSize);
    }
}

确保Spring Boot 应用程序中配置了 MyBatis-Plus 的分页插件,以支持分页功能,可以在配置类中添加以下代码

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}

通过以上的配置及代码,可访问/users?pageNum=1&pageSize=10(省略了前缀),可得包含分页信息的返回结果,示例如下

{
    "current": 1,
    "size": 10,
    "total": 100,
    "records": [
        {
            "id": 1,
            "name": "John",
            "age": 25,
            "email": "john@example.com"
        },
        // 其他用户记录...
    ]
}

批量操作

BaseMapper 支持批量插入、更新和删除操作,可以提高数据处理的效率。例如,批量插入可以通过 insertBatch 方法实现,批量更新可以通过 updateBatchById 方法实现,批量删除可以通过deleteBatchIds 方法实现。示例如下:
与上述案例相同,省去实体类和Mapper接口。
创建 UserService 类,使用 UserMapper 进行批量插入、更新和删除操作

@Service
public class UserService extends ServiceImpl<UserMapper, User> {

    // 批量插入
    public void insertBatch(List<User> userList) {
        this.saveBatch(userList); // 使用 saveBatch 方法进行批量插入
    }

    // 批量更新
    public void updateBatch(List<User> userList) {
        this.updateBatchById(userList); // 使用 updateBatchById 方法进行批量更新
    }

    // 批量删除
    public void deleteBatch(List<Long> ids) {
        this.removeByIds(ids); // 使用 removeByIds 方法进行批量删除
    }
}

在控制器中调用 UserService 进行批量操作

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    // 批量插入
    @PostMapping("/batch")
    public void insertBatch(@RequestBody List<User> userList) {
        userService.insertBatch(userList);
    }

    // 批量更新
    @PutMapping("/batch")
    public void updateBatch(@RequestBody List<User> userList) {
        userService.updateBatch(userList);
    }

    // 批量删除
    @DeleteMapping("/batch")
    public void deleteBatch(@RequestBody List<Long> ids) {
        userService.deleteBatch(ids);
    }
}

通过如上的配置可以通过如下请求来测试
批量插入

POST /users/batch
Content-Type: application/json

[
    {"name": "Alice", "age": 30, "email": "alice@example.com"},
    {"name": "Bob", "age": 25, "email": "bob@example.com"},
    {"name": "Charlie", "age": 28, "email": "charlie@example.com"}
]

批量更新

PUT /users/batch
Content-Type: application/json

[
    {"id": 1, "name": "Alice Smith", "age": 31, "email": "alice.smith@example.com"},
    {"id": 2, "name": "Bob Brown", "age": 26, "email": "bob.brown@example.com"}
]

批量删除

DELETE /users/batch
Content-Type: application/json

[1, 2, 3]  // 要删除的用户 ID 列表

逻辑删除

MyBatis-Plus 支持逻辑删除功能,可以通过在实体类的字段上添加 @TableLogic 注解来指定逻辑删除的字段,并在全局配置中启用逻辑删除功能。BaseMapper 支持根据条件进行逻辑删除操作,例如,selectPage 方法可以通过指定查询条件来查询被逻辑删除的记录。示例如下:
创建 User 实体类,并在需要逻辑删除的字段上添加 @TableLogic 注解

@Data
@TableName("user")
public class User {
    @TableId
    private Long id;

    private String name;
    private Integer age;
    private String email;

    @TableLogic // 逻辑删除字段
    private Integer deleted; // 1 表示已删除,0 表示未删除
}

创建 UserMapper 接口,继承 BaseMapper

public interface UserMapper extends BaseMapper<User> {

}

创建 UserService 类,使用 UserMapper 进行逻辑删除操作

@Service
public class UserService extends ServiceImpl<UserMapper, User> {

    // 逻辑删除
    public void deleteUser(Long id) {
        this.removeById(id); // 使用 removeById 方法进行逻辑删除
    }

    // 查询所有用户(包括已删除的用户)
    public List<User> getAllUsers() {
        return this.list(); // 查询所有用户
    }
}

在控制器中调用 UserService 进行逻辑删除和查询操作

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    // 逻辑删除
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }

    // 查询所有用户(包括已删除的用户)
    @GetMapping("/all")
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }
}

在 MyBatis-Plus 的配置类中启用逻辑删除功能(通常在 application.yml 或 application.properties 中配置)

mybatis-plus:
  global-config:
    db-config:
      logic-delete-value: 1   # 逻辑删除的值
      logic-not-delete-value: 0 # 未删除的值

通过上述的配置可实现逻辑删除与查询

DELETE /users/{id}

GET /users/all

乐观锁

MyBatis-Plus 支持乐观锁功能,可以通过在实体类的字段上添加 @Version 注解来指定乐观锁的字段,并在全局配置中启用乐观锁功能。BaseMapper 提供了根据乐观锁字段进行更新操作的方法,例如,updateById 方法可以通过乐观锁字段来实现乐观锁更新。示例如下:
创建 User 实体类,并在需要进行乐观锁的字段上添加 @Version 注解

@Data
@TableName("user")
public class User {
    @TableId
    private Long id;

    private String name;
    private Integer age;
    private String email;

    @Version // 乐观锁字段
    private Integer version; // 版本号
}

创建 UserMapper 接口,继承 BaseMapper

public interface UserMapper extends BaseMapper<User> {

}

创建 UserService 类,使用 UserMapper 进行乐观锁更新操作

@Service
public class UserService extends ServiceImpl<UserMapper, User> {

    // 更新用户信息(乐观锁)
    public boolean updateUser(User user) {
        return this.updateById(user); // 使用 updateById 方法进行乐观锁更新
    }
}

在控制器中调用 UserService 进行更新操作

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    // 更新用户信息
    @PutMapping
    public boolean updateUser(@RequestBody User user) {
        return userService.updateUser(user);
    }
}

通过上述配置,可模拟请求如下:

PUT /users
Content-Type: application/json

{
    "id": 1,
    "name": "Alice Smith",
    "age": 31,
    "email": "alice.smith@example.com",
    "version": 1  // 提交时需要提供当前的版本号
}

乐观锁的更新机制:在执行更新时,MyBatis-Plus 会自动检查 version 字段的值。如果数据库中的 version 值与传入的值不匹配,则更新操作会失败,返回 0(表示没有更新任何记录)。这可以有效防止并发更新导致的数据不一致问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值