跳到主要内容

基础 CRUD 操作

本章将详细介绍 MyBatis Plus 的基础 CRUD(增删改查)操作,这是使用 MyBatis Plus 最核心的功能。

BaseMapper 接口

MyBatis Plus 提供了 BaseMapper 接口,它封装了大部分常用的 CRUD 方法。只需让 Mapper 接口继承 BaseMapper,就能获得丰富的数据库操作能力。

继承 BaseMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

继承 BaseMapper 后,无需编写任何 XML 或注解,就自动拥有了以下方法:

方法说明
insert(T entity)插入一条记录
deleteById(Serializable id)根据 ID 删除
deleteByMap(Map<String, Object> columnMap)根据 map 条件删除
delete(Wrapper<T> wrapper)根据条件删除
deleteBatchIds(Collection<? extends Serializable> idList)根据 ID 批量删除
updateById(T entity)根据 ID 更新
update(T entity, Wrapper<T> updateWrapper)根据条件更新
selectById(Serializable id)根据 ID 查询
selectBatchIds(Collection<? extends Serializable> idList)根据 ID 批量查询
selectByMap(Map<String, Object> columnMap)根据 map 条件查询
selectOne(Wrapper<T> queryWrapper)根据条件查询一条
selectList(Wrapper<T> queryWrapper)根据条件查询列表
selectCount(Wrapper<T> queryWrapper)根据条件查询总数
selectMaps(Wrapper<T> queryWrapper)根据条件查询返回 Map
selectPage(Page<T> page, Wrapper<T> queryWrapper)分页查询

实体类定义

基本实体类

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;

@Data
@TableName("t_user")
public class User {

@TableId(type = IdType.AUTO)
private Long id;

private String name;

private Integer age;

private String email;

@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;

@TableLogic
private Integer deleted;

@Version
private Integer version;
}

常用注解说明

注解说明
@TableName指定表名,默认类名驼峰转下划线
@TableId指定主键,type 指定主键策略
@TableField指定字段映射,exist = false 表示非表字段
@TableLogic逻辑删除字段
@Version乐观锁字段

主键策略

public enum IdType {
AUTO, // 数据库自增
NONE, // 无状态,默认
INPUT, // 用户输入
ASSIGN_ID, // 分配 ID(雪花算法)
ASSIGN_UUID // 分配 UUID
}

// 使用示例
@TableId(type = IdType.AUTO)
private Long id;

@TableId(type = IdType.ASSIGN_ID)
private Long id;

@TableId(type = IdType.INPUT)
private Long id;

插入操作

基本插入

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class InsertTest {

@Autowired
private UserMapper userMapper;

@Test
void testInsert() {
User user = new User();
user.setName("张三");
user.setAge(25);
user.setEmail("[email protected]");

int result = userMapper.insert(user);

System.out.println("影响行数:" + result);
System.out.println("自动生成的 ID:" + user.getId());
}
}

批量插入

MyBatis Plus 3.5.0+ 支持 saveBatch 批量插入,需要配合 Service 层使用:

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

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

// 使用
@SpringBootTest
class BatchInsertTest {

@Autowired
private UserService userService;

@Test
void testBatchInsert() {
List<User> users = new ArrayList<>();
for (int i = 0; i < 100; i++) {
User user = new User();
user.setName("用户" + i);
user.setAge(20 + i % 30);
user.setEmail("user" + i + "@example.com");
users.add(user);
}

boolean success = userService.saveBatch(users);
System.out.println("批量插入结果:" + success);
}

@Test
void testBatchInsertWithBatchSize() {
List<User> users = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
User user = new User();
user.setName("用户" + i);
user.setAge(20 + i % 30);
user.setEmail("user" + i + "@example.com");
users.add(user);
}

boolean success = userService.saveBatch(users, 100);
System.out.println("批量插入结果:" + success);
}
}

删除操作

根据 ID 删除

@Test
void testDeleteById() {
int result = userMapper.deleteById(1L);
System.out.println("删除结果:" + result);
}

根据 ID 批量删除

@Test
void testDeleteBatchIds() {
List<Long> ids = Arrays.asList(1L, 2L, 3L);
int result = userMapper.deleteBatchIds(ids);
System.out.println("批量删除结果:" + result);
}

根据 Map 条件删除

@Test
void testDeleteByMap() {
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("name", "张三");
columnMap.put("age", 25);

int result = userMapper.deleteByMap(columnMap);
System.out.println("根据条件删除结果:" + result);
}

根据 Wrapper 条件删除

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

@Test
void testDeleteByWrapper() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "张三")
.gt("age", 20);

int result = userMapper.delete(wrapper);
System.out.println("根据条件删除结果:" + result);
}

逻辑删除

配置逻辑删除后,删除操作会变成更新操作:

@Data
@TableName("t_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;

private String name;

@TableLogic
private Integer deleted;
}

// 配置全局逻辑删除
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0

// 测试
@Test
void testLogicDelete() {
int result = userMapper.deleteById(1L);
System.out.println("逻辑删除结果:" + result);
}

执行 SQL:

UPDATE t_user SET deleted = 1 WHERE id = 1 AND deleted = 0

更新操作

根据 ID 更新

@Test
void testUpdateById() {
User user = new User();
user.setId(1L);
user.setName("李四");
user.setAge(30);

int result = userMapper.updateById(user);
System.out.println("更新结果:" + result);
}

注意:updateById 只更新非 null 字段。如果需要将字段更新为 null,需要使用 UpdateWrapper 或添加 @TableField(updateStrategy = FieldStrategy.IGNORED)

根据 Wrapper 更新

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;

@Test
void testUpdateByWrapper() {
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("name", "张三")
.set("age", 26)
.set("email", "[email protected]");

int result = userMapper.update(null, wrapper);
System.out.println("更新结果:" + result);
}

更新为 NULL 值

@Test
void testUpdateToNull() {
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("id", 1L)
.set("email", null);

int result = userMapper.update(null, wrapper);
System.out.println("更新为 NULL 结果:" + result);
}

Lambda 方式更新

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;

@Test
void testLambdaUpdate() {
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(User::getName, "张三")
.set(User::getAge, 26)
.set(User::getEmail, "[email protected]");

int result = userMapper.update(null, wrapper);
System.out.println("Lambda 更新结果:" + result);
}

乐观锁更新

@Data
@TableName("t_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;

private String name;

@Version
private Integer version;
}

// 配置乐观锁插件
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}

// 测试
@Test
void testOptimisticLock() {
User user = userMapper.selectById(1L);
user.setName("新名字");

int result = userMapper.updateById(user);
System.out.println("乐观锁更新结果:" + result);
}

执行 SQL:

UPDATE t_user SET name = '新名字', version = version + 1 
WHERE id = 1 AND version = 旧版本号

查询操作

根据 ID 查询

@Test
void testSelectById() {
User user = userMapper.selectById(1L);
System.out.println(user);
}

根据 ID 批量查询

@Test
void testSelectBatchIds() {
List<Long> ids = Arrays.asList(1L, 2L, 3L);
List<User> users = userMapper.selectBatchIds(ids);
users.forEach(System.out::println);
}

根据 Map 条件查询

@Test
void testSelectByMap() {
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("name", "张三");
columnMap.put("age", 25);

List<User> users = userMapper.selectByMap(columnMap);
users.forEach(System.out::println);
}

查询所有

@Test
void testSelectAll() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}

条件查询

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

@Test
void testSelectByCondition() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "张三")
.gt("age", 20)
.orderByDesc("create_time");

List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}

Lambda 条件查询

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

@Test
void testLambdaSelect() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getName, "张三")
.gt(User::getAge, 20)
.orderByDesc(User::getCreateTime);

List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}

查询一条记录

@Test
void testSelectOne() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getName, "张三");

User user = userMapper.selectOne(wrapper);
System.out.println(user);
}

注意:如果查询结果有多条,会抛出异常。

查询总数

@Test
void testSelectCount() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.gt(User::getAge, 20);

Long count = userMapper.selectCount(wrapper);
System.out.println("总数:" + count);
}

查询返回 Map

@Test
void testSelectMaps() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.select(User::getId, User::getName, User::getAge)
.gt(User::getAge, 20);

List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}

指定查询字段

@Test
void testSelectSpecificFields() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.select(User::getId, User::getName)
.gt(User::getAge, 20);

List<User> users = userMapper.selectList(wrapper);
users.forEach(u -> System.out.println(u.getId() + ": " + u.getName()));
}

Service 层 CRUD

MyBatis Plus 提供了 IService 接口和 ServiceImpl 实现类,封装了更多业务方法。

定义 Service 接口

import com.baomidou.mybatisplus.extension.service.IService;

public interface UserService extends IService<User> {
}

实现 Service 类

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

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

Service 层常用方法

@SpringBootTest
class ServiceTest {

@Autowired
private UserService userService;

@Test
void testSave() {
User user = new User();
user.setName("王五");
user.setAge(28);

boolean success = userService.save(user);
System.out.println("保存结果:" + success);
}

@Test
void testSaveBatch() {
List<User> users = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User user = new User();
user.setName("用户" + i);
user.setAge(20 + i);
users.add(user);
}

boolean success = userService.saveBatch(users);
System.out.println("批量保存结果:" + success);
}

@Test
void testSaveOrUpdate() {
User user = new User();
user.setId(1L);
user.setName("更新后的名字");

boolean success = userService.saveOrUpdate(user);
System.out.println("保存或更新结果:" + success);
}

@Test
void testRemoveById() {
boolean success = userService.removeById(1L);
System.out.println("删除结果:" + success);
}

@Test
void testUpdateById() {
User user = new User();
user.setId(1L);
user.setName("新名字");

boolean success = userService.updateById(user);
System.out.println("更新结果:" + success);
}

@Test
void testGetById() {
User user = userService.getById(1L);
System.out.println(user);
}

@Test
void testList() {
List<User> users = userService.list();
users.forEach(System.out::println);
}

@Test
void testListByCondition() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.gt(User::getAge, 20);

List<User> users = userService.list(wrapper);
users.forEach(System.out::println);
}

@Test
void testCount() {
long count = userService.count();
System.out.println("总数:" + count);
}
}

自动填充

自动填充可以在插入或更新时自动设置字段值。

配置自动填充处理器

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "createBy", String.class, getCurrentUserId());
}

@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictUpdateFill(metaObject, "updateBy", String.class, getCurrentUserId());
}

private String getCurrentUserId() {
return "system";
}
}

实体类配置

@Data
@TableName("t_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;

private String name;

@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;

@TableField(fill = FieldFill.INSERT)
private String createBy;

@TableField(fill = FieldFill.UPDATE)
private String updateBy;
}

小结

本章我们学习了:

  1. BaseMapper:继承即可获得 CRUD 方法
  2. 实体类注解@TableName@TableId@TableField
  3. 插入操作:单条插入、批量插入
  4. 删除操作:根据 ID、Map、Wrapper 删除,逻辑删除
  5. 更新操作:根据 ID、Wrapper 更新,乐观锁
  6. 查询操作:各种条件查询、指定字段查询
  7. Service 层:更丰富的业务方法
  8. 自动填充:自动设置创建时间、更新时间等

参考资源