基础 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;
}
小结
本章我们学习了:
- BaseMapper:继承即可获得 CRUD 方法
- 实体类注解:
@TableName、@TableId、@TableField等 - 插入操作:单条插入、批量插入
- 删除操作:根据 ID、Map、Wrapper 删除,逻辑删除
- 更新操作:根据 ID、Wrapper 更新,乐观锁
- 查询操作:各种条件查询、指定字段查询
- Service 层:更丰富的业务方法
- 自动填充:自动设置创建时间、更新时间等