一、核心概念
概念 | 说明 |
---|---|
insert(T entity) |
BaseMapper 提供的插入方法,返回影响行数(成功为1) |
@TableId |
标识主键字段,决定 ID 生成策略(如自增、雪花算法) |
IdType |
主键策略枚举,如 AUTO , NONE , ID_WORKER , UUID 等 |
save(T entity) |
IService 接口提供的插入方法,封装了 insert |
saveBatch(Collection<T> entityList, int batchSize) |
批量插入,提升性能 |
@TableField(fill = FieldFill.INSERT) |
自动填充字段(如创建时间) |
返回值 | 插入成功返回 1 ,失败返回 0 或抛出异常 |
二、详细操作步骤(Spring Boot + MySQL)
步骤 1:准备数据库表
CREATE DATABASE mydemo;
USE mydemo;
CREATE TABLE user (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
age INT,
email VARCHAR(100),
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
步骤 2:创建实体类 User.java
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("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;
}
🔔 说明:
@TableId(type = IdType.AUTO)
:使用数据库自增主键@TableField(fill = ...)
:标记自动填充字段
步骤 3:实现自动填充处理器
创建类 MyMetaObjectHandler.java
:
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
✅
strictInsertFill
是推荐方式,避免 NPE。
步骤 4:创建 Mapper 接口
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 无需写方法,BaseMapper 已提供 insert 方法
}
步骤 5:配置 application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydemo?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开发环境打印 SQL
步骤 6:编写插入逻辑(Controller 示例)
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserMapper userMapper;
// 单条插入
@PostMapping
public String insertUser(@RequestBody User user) {
int result = userMapper.insert(user);
if (result == 1) {
return "插入成功,ID: " + user.getId();
} else {
return "插入失败";
}
}
// 批量插入
@PostMapping("/batch")
public String insertBatch(@RequestBody List<User> users) {
boolean result = userService.saveBatch(users, 100); // 每100条提交一次
return result ? "批量插入成功" : "批量插入失败";
}
}
🔔 注意:
userMapper.insert(user)
执行后,主键 ID 会自动回填到user
对象中(如自增或雪花 ID)。
三、常见错误与解决方案
错误 | 原因 | 解决方案 |
---|---|---|
Field 'name' doesn't have a default value |
非空字段未赋值 | 插入前确保必填字段有值 |
Duplicate entry 'xxx' for key 'PRIMARY' |
主键冲突 | 检查主键策略是否正确(如不要手动设置自增主键) |
Unknown column 'create_time' in 'field list' |
字段名不匹配 | 使用 @TableField("db_column") 映射 |
自动填充字段为空 | 未启用 MetaObjectHandler |
确保处理器类被 @Component 扫描到 |
批量插入性能差 | 未使用 rewriteBatchedStatements=true |
在 JDBC URL 中添加该参数 |
四、注意事项
主键策略选择:
AUTO
:数据库自增(MySQL 推荐)ID_WORKER
:分布式系统推荐(雪花算法)ASSIGN_ID
:MP 默认,使用雪花算法生成 Long 型 IDUUID
:字符串主键
不要手动设置自增主键:如果使用
IdType.AUTO
,插入时id
应为null
。批量插入建议使用
saveBatch
:基于IService
,支持分批提交。JDBC URL 优化批量插入性能:
rewriteBatchedStatements=true
启用后,JDBC 会将多条
INSERT
合并为一条,显著提升性能。示例:
jdbc:mysql://localhost:3306/mydemo?...&rewriteBatchedStatements=true
事务控制:插入操作通常需要事务支持,Spring Boot 默认方法级事务。
五、使用技巧
✅ 1. 获取插入后的主键 ID
User user = new User();
user.setName("张三");
user.setAge(25);
user.setEmail("zhangsan@example.com");
userMapper.insert(user); // 执行插入
System.out.println("插入后的主键ID: " + user.getId()); // 自动回填
适用于
AUTO
、ID_WORKER
、UUID
等所有支持回填的策略。
✅ 2. 批量插入优化(JDBC + rewrite)
确保 JDBC URL 包含:
url: jdbc:mysql://localhost:3306/mydemo?...&rewriteBatchedStatements=true
Java 代码:
List<User> users = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
User u = new User();
u.setName("用户" + i);
u.setAge(20 + i % 30);
u.setEmail("user" + i + "@example.com");
users.add(u);
}
long start = System.currentTimeMillis();
userService.saveBatch(users, 500); // 每500条一批
System.out.println("批量插入耗时: " + (System.currentTimeMillis() - start) + "ms");
⏱️ 性能对比:开启
rewriteBatchedStatements=true
后,插入 1000 条数据可从 2s 降至 200ms 以内。
✅ 3. 使用 insertBatchSomeColumn
(3.5.3+)
适用于只插入部分字段的批量操作:
List<User> users = ...;
userMapper.insertBatchSomeColumn(users, User::getName, User::getAge); // 只插入 name 和 age
六、最佳实践与性能优化
实践 | 说明 |
---|---|
✅ 使用 saveBatch 进行批量插入 |
减少数据库交互次数 |
✅ 开启 rewriteBatchedStatements=true |
提升批量插入性能 5~10 倍 |
✅ 合理设置 batchSize (建议 100~500) |
避免内存溢出或事务过大 |
✅ 使用 @TableField(fill = ...) 实现自动填充 |
避免手动设置时间字段 |
✅ 主键使用 IdType.AUTO 或 IdType.ASSIGN_ID |
保证唯一性和性能 |
✅ 插入前校验数据合法性 | 防止数据库约束异常 |
✅ 结合事务控制 | 确保数据一致性 |
✅ 生产环境关闭 SQL 日志 | 避免日志爆炸 |
七、扩展:插入时忽略某些字段
使用 @TableField(exist = false)
或 @TableField(select = false)
控制字段行为:
@TableField(exist = false)
private String notInDbField; // 不映射到数据库
@TableField(select = false, insert = false, update = false)
private String ignoreAll; // 所有操作都忽略
八、总结:插入操作关键点
场景 | 推荐方式 |
---|---|
单条插入 | mapper.insert(entity) |
批量插入 | service.saveBatch(list, batchSize) |
主键生成 | @TableId(type = IdType.AUTO) (自增)或 ASSIGN_ID (雪花) |
自动填充 | 实现 MetaObjectHandler |
性能优化 | JDBC 添加 rewriteBatchedStatements=true |
字段控制 | 使用 @TableField 注解 |
异常处理 | 捕获 DataAccessException 或 PersistenceException |