【MyBatis Plus | 1-完整使用指南】

MyBatis Plus 使用全解析

MyBatis Plus 完整使用指南

MyBatis Plus 是一个强大的 MyBatis 增强工具,简化开发、提高效率。下面详细介绍其使用方法:

1. 快速开始

1.1 添加依赖

Maven:

<dependencies>
    <!-- MyBatis Plus 核心依赖 -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.3.1</version>
    </dependency>
    
    <!-- 代码生成器(可选) -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.5.3.1</version>
    </dependency>
    
    <!-- 模板引擎(代码生成需要) -->
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.32</version>
    </dependency>
</dependencies>

Gradle:

dependencies {
    implementation 'com.baomidou:mybatis-plus-boot-starter:3.5.3.1'
    implementation 'com.baomidou:mybatis-plus-generator:3.5.3.1'
    implementation 'org.freemarker:freemarker:2.3.32'
}

1.2 基础配置

application.yml:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/reggie?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 打印 SQL 日志
    map-underscore-to-camel-case: true  # 下划线转驼峰
  global-config:
    db-config:
      id-type: auto  # 主键策略:AUTO-数据库自增,INPUT-手动输入,ASSIGN_ID-雪花算法
      logic-delete-field: deleted  # 逻辑删除字段
      logic-delete-value: 1  # 逻辑已删除值
      logic-not-delete-value: 0  # 逻辑未删除值

2. 实体类映射

2.1 基础实体类

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 username;
    private String password;
    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;
    
    // 排除非表字段
    @TableField(exist = false)
    private String confirmPassword;
}

2.2 枚举类型处理

// 枚举定义
public enum GenderEnum {
    MALE(1, "男"),
    FEMALE(2, "女");
    
    private final Integer code;
    private final String desc;
    
    GenderEnum(Integer code, String desc) {
        this.code = code;
        this.desc = desc;
    }
    
    // getter...
}

// 实体类中使用枚举
@Data
@TableName("user")
public class User {
    // 自动映射枚举的 code 值到数据库
    private GenderEnum gender;
}

3. Mapper 接口

3.1 基础 Mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;

// 继承 BaseMapper 即拥有基础的 CRUD 方法
public interface UserMapper extends BaseMapper<User> {
    // 可以自定义方法
    List<User> selectByAgeGreaterThan(@Param("age") Integer age);
}

3.2 自定义 SQL

public interface UserMapper extends BaseMapper<User> {
    
    // 使用注解方式
    @Select("SELECT * FROM user WHERE age > #{age}")
    List<User> selectByAge(@Param("age") Integer age);
    
    // 使用 XML 方式(推荐复杂 SQL)
    List<User> selectComplexQuery(UserQuery query);
}

对应的 XML:

<!-- resources/mapper/UserMapper.xml -->
<?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.rongx.reggie.mapper.UserMapper">
    
    <select id="selectComplexQuery" resultType="com.rongx.reggie.entity.User">
        SELECT * FROM user 
        <where>
            <if test="username != null and username != ''">
                AND username LIKE CONCAT('%', #{username}, '%')
            </if>
            <if test="minAge != null">
                AND age >= #{minAge}
            </if>
            <if test="maxAge != null">
                AND age <= #{maxAge}
            </if>
        </where>
        ORDER BY create_time DESC
    </select>
</mapper>

4. Service 层

4.1 基础 Service

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

// 服务接口继承 IService
public interface UserService extends IService<User> {
    // 自定义业务方法
    boolean register(User user);
    User login(String username, String password);
}

// 实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
    @Override
    public boolean register(User user) {
        // 检查用户名是否已存在
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, user.getUsername());
        User existing = getOne(wrapper);
        
        if (existing != null) {
            throw new BusinessException("用户名已存在");
        }
        
        // 密码加密等业务逻辑
        user.setPassword(encodePassword(user.getPassword()));
        
        return save(user);
    }
    
    @Override
    public User login(String username, String password) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, username);
        User user = getOne(wrapper);
        
        if (user == null || !verifyPassword(password, user.getPassword())) {
            throw new BusinessException("用户名或密码错误");
        }
        
        return user;
    }
    
    private String encodePassword(String password) {
        // 密码加密逻辑
        return password; // 实际使用 BCrypt 等加密
    }
    
    private boolean verifyPassword(String input, String encoded) {
        // 密码验证逻辑
        return input.equals(encoded);
    }
}

5. 核心 CRUD 操作

5.1 查询操作

@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    // 1. 根据ID查询
    public User getById(Long id) {
        return userMapper.selectById(id);
    }
    
    // 2. 查询所有
    public List<User> getAll() {
        return userMapper.selectList(null);
    }
    
    // 3. 条件查询
    public List<User> getByCondition(String username, Integer minAge) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(username), User::getUsername, username)
               .ge(minAge != null, User::getAge, minAge)
               .orderByDesc(User::getCreateTime);
        return userMapper.selectList(wrapper);
    }
    
    // 4. 分页查询
    public Page<User> getPage(int current, int size, String keyword) {
        Page<User> page = new Page<>(current, size);
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotBlank(keyword), User::getUsername, keyword)
               .or()
               .like(StringUtils.isNotBlank(keyword), User::getEmail, keyword);
        return userMapper.selectPage(page, wrapper);
    }
    
    // 5. 统计查询
    public long countByAge(Integer age) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(age != null, User::getAge, age);
        return userMapper.selectCount(wrapper);
    }
}

5.2 新增操作

public class UserService {
    
    // 1. 插入一条记录
    public boolean saveUser(User user) {
        return userMapper.insert(user) > 0;
    }
    
    // 2. 批量插入
    public boolean saveBatch(List<User> users) {
        return userMapper.insertBatchSomeColumn(users) > 0; // 需要配置注入器
    }
    
    // 3. 插入或更新
    public boolean saveOrUpdate(User user) {
        return userMapper.insertOrUpdate(user) > 0;
    }
}

5.3 更新操作

public class UserService {
    
    // 1. 根据ID更新
    public boolean updateById(User user) {
        return userMapper.updateById(user) > 0;
    }
    
    // 2. 条件更新
    public boolean updateByCondition(User user) {
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getUsername, user.getUsername())
               .set(User::getAge, user.getAge())
               .set(User::getEmail, user.getEmail());
        return userMapper.update(null, wrapper) > 0;
    }
    
    // 3. 字段自增/自减
    public boolean incrementAge(Long userId) {
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getId, userId)
               .setSql("age = age + 1");
        return userMapper.update(null, wrapper) > 0;
    }
}

5.4 删除操作

public class UserService {
    
    // 1. 根据ID删除
    public boolean removeById(Long id) {
        return userMapper.deleteById(id) > 0;
    }
    
    // 2. 条件删除
    public boolean removeByCondition(String username) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, username);
        return userMapper.delete(wrapper) > 0;
    }
    
    // 3. 批量删除
    public boolean removeByIds(List<Long> ids) {
        return userMapper.deleteBatchIds(ids) > 0;
    }
    
    // 4. 逻辑删除(需要配置逻辑删除字段)
    public boolean logicRemoveById(Long id) {
        return userMapper.deleteById(id) > 0; // 自动转为逻辑删除
    }
}

6. 条件构造器详解

6.1 LambdaQueryWrapper

public void queryExamples() {
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    
    // 等值查询
    wrapper.eq(User::getUsername, "admin");
    
    // 不等查询
    wrapper.ne(User::getStatus, 0);
    
    // 大于、小于
    wrapper.gt(User::getAge, 18)
           .lt(User::getAge, 60);
    
    // 范围查询
    wrapper.between(User::getAge, 20, 30);
    
    // 模糊查询
    wrapper.like(User::getUsername, "张")
           .likeLeft(User::getEmail, "@gmail.com")   // %@gmail.com
           .likeRight(User::getPhone, "138");        // 138%
    
    // IN 查询
    wrapper.in(User::getRole, Arrays.asList("admin", "user"));
    
    // 空值判断
    wrapper.isNull(User::getDeleteTime)
           .isNotNull(User::getUpdateTime);
    
    // 分组和排序
    wrapper.groupBy(User::getDeptId)
           .orderByAsc(User::getAge)
           .orderByDesc(User::getCreateTime);
    
    // 分页
    wrapper.last("LIMIT 10");
    
    List<User> users = userMapper.selectList(wrapper);
}

6.2 LambdaUpdateWrapper

public void updateExamples() {
    LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
    
    // 设置更新字段
    wrapper.set(User::getAge, 25)
           .set(User::getEmail, "new@email.com");
    
    // 条件更新
    wrapper.eq(User::getId, 1L);
    
    // SQL 表达式
    wrapper.setSql("balance = balance + 100");
    
    userMapper.update(null, wrapper);
}

7. 分页查询

7.1 配置分页插件

@Configuration
public class MybatisPlusConfig {
    
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        
        // 分页插件
        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        paginationInterceptor.setMaxLimit(1000L); // 单页分页条数限制
        paginationInterceptor.setOverflow(true);  // 页码超出后处理
        
        interceptor.addInnerInterceptor(paginationInterceptor);
        
        // 乐观锁插件(可选)
        OptimisticLockerInnerInterceptor optimisticLockerInterceptor = new OptimisticLockerInnerInterceptor();
        interceptor.addInnerInterceptor(optimisticLockerInterceptor);
        
        return interceptor;
    }
}

7.2 分页使用

@RestController
@RequestMapping("/user")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/page")
    public R<Page<User>> getPage(
            @RequestParam(defaultValue = "1") int current,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(required = false) String keyword) {
        
        Page<User> page = new Page<>(current, size);
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        
        if (StringUtils.isNotBlank(keyword)) {
            wrapper.like(User::getUsername, keyword)
                   .or()
                   .like(User::getEmail, keyword);
        }
        
        Page<User> result = userService.page(page, wrapper);
        return R.success(result);
    }
}

8. 自动填充功能

8.1 实现 MetaObjectHandler

@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, "createUser", Long.class, getCurrentUserId());
        this.strictInsertFill(metaObject, "updateUser", Long.class, getCurrentUserId());
    }
    
    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        this.strictUpdateFill(metaObject, "updateUser", Long.class, getCurrentUserId());
    }
    
    private Long getCurrentUserId() {
        // 从安全上下文获取当前用户ID
        // 例如:return SecurityUtils.getCurrentUserId();
        return 1L; // 示例
    }
}

9. 代码生成器

9.1 快速生成代码

public class CodeGenerator {
    
    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator generator = new AutoGenerator();
        
        // 全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        globalConfig.setOutputDir(projectPath + "/src/main/java");
        globalConfig.setAuthor("rongx");
        globalConfig.setOpen(false);
        globalConfig.setSwagger2(true);
        generator.setGlobalConfig(globalConfig);
        
        // 数据源配置
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/reggie?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai");
        dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("123456");
        generator.setDataSource(dataSourceConfig);
        
        // 包配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setParent("com.rongx.reggie");
        packageConfig.setEntity("entity");
        packageConfig.setMapper("mapper");
        packageConfig.setService("service");
        packageConfig.setServiceImpl("service.impl");
        packageConfig.setController("controller");
        generator.setPackageInfo(packageConfig);
        
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        strategy.setInclude("user", "order", "product"); // 要生成的表
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix("t_"); // 表前缀
        generator.setStrategy(strategy);
        
        // 模板配置
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setXml(null); // 不生成 XML,使用注解方式
        generator.setTemplate(templateConfig);
        
        // 执行生成
        generator.execute();
    }
}

10. 完整示例项目结构

src/main/java/com/rongx/reggie/
├── entity/          # 实体类
│   ├── User.java
│   └── Product.java
├── mapper/          # Mapper 接口
│   ├── UserMapper.java
│   └── ProductMapper.java
├── service/         # Service 接口
│   ├── UserService.java
│   └── ProductService.java
├── service/impl/    # Service 实现
│   ├── UserServiceImpl.java
│   └── ProductServiceImpl.java
├── controller/      # 控制器
│   ├── UserController.java
│   └── ProductController.java
└── config/          # 配置类
    ├── MybatisPlusConfig.java
    └── MyMetaObjectHandler.java

11. 常用注解总结

注解作用示例
@TableName指定表名@TableName("user")
@TableId主键注解@TableId(type = IdType.AUTO)
@TableField字段注解@TableField(fill = FieldFill.INSERT)
@TableLogic逻辑删除@TableLogic
@Version乐观锁@Version
@EnumValue枚举值@EnumValue

12. 最佳实践

  1. 使用 Lambda 表达式:避免字段名硬编码
  2. 合理使用 Service 层:业务逻辑放在 Service
  3. 配置合理的插件:分页、乐观锁等
  4. 统一异常处理:处理 MyBatis Plus 异常
  5. 性能优化:合理使用索引,避免 N+1 查询

MyBatis Plus 大大简化了数据库操作,通过合理使用可以显著提高开发效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值