一、核心概念

概念 说明
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 中添加该参数

四、注意事项

  1. 主键策略选择

    • AUTO:数据库自增(MySQL 推荐)
    • ID_WORKER:分布式系统推荐(雪花算法)
    • ASSIGN_ID:MP 默认,使用雪花算法生成 Long 型 ID
    • UUID:字符串主键
  2. 不要手动设置自增主键:如果使用 IdType.AUTO,插入时 id 应为 null

  3. 批量插入建议使用 saveBatch:基于 IService,支持分批提交。

  4. JDBC URL 优化批量插入性能

    rewriteBatchedStatements=true
    

    启用后,JDBC 会将多条 INSERT 合并为一条,显著提升性能。

    示例:

    jdbc:mysql://localhost:3306/mydemo?...&rewriteBatchedStatements=true
    
  5. 事务控制:插入操作通常需要事务支持,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()); // 自动回填

适用于 AUTOID_WORKERUUID 等所有支持回填的策略。


✅ 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.AUTOIdType.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 注解
异常处理 捕获 DataAccessExceptionPersistenceException