副标题:从“写 SQL 写到头秃”到“一行代码查全表”,MyBatis-Plus 让我提前进入退休生活(不是)

大家好,我是 Qcby,一个曾经每天和 SELECT * FROM user WHERE id = ? 斗智斗勇的 Java 程序员。
直到有一天,我遇到了 MyBatis-Plus(简称 MP) —— 这哪是框架?这分明是我的“摸鱼外挂”!

今天就带大家看看,如何用 MP 把 CRUD 变成“复制粘贴”,顺便把分页、乐观锁、逻辑删除、枚举统统安排得明明白白!


🚀 1. 起飞前准备:加个依赖,扫个包

首先,Maven 里加个“魔法粉”:

xml

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.7</version>
</dependency>

然后在启动类上贴个“召唤符”:

java

@MapperScan("com.qcby.mybatisplusdemo.mapper")

搞定!MP 已经在后台默默为你打工了。


👤 2. 实体类:注解一加,字段自动对齐!

以前写实体类,总要担心:

“数据库字段是 user_name,我 Java 属性写 userName,会不会查不到?”
“主键是不是自增?要不要手动设 ID?”
“删用户真的要物理删?不怕老板半夜打电话?”

现在?注解安排!

java

@Data
public class User {

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

    @TableField("username") // 数据库叫 username,我偏要叫 name!
    private String name;

    private Integer age;
    private String email;

    private SexEnum sex; // 枚举?小菜一碟!

    @TableLogic // 逻辑删除:删了但没完全删
    private Integer isDeleted;

    @TableField(exist = false) // 这个字段只存在于我的幻想中(比如确认密码)
    private String confirmPassword;
}

看懂了吗?

  • @TableId:主键策略,AUTO 表示“数据库你看着办”。
  • @TableField("xxx"):字段名不一致?我来桥接!
  • @TableLogic:删除?不存在的!只是把 isDeleted 改成 1 而已~
  • exist = false:这个字段纯属“精神寄托”,数据库里根本没有!

💡 小知识:MP 默认开启 驼峰转下划线,所以 createTime → create_time 自动映射,根本不用写注解!


🔌 3. 插件全家桶:分页 + 乐观锁,一键启用!

在 MybatisPlusConfig.java 里,我们装两个“外挂”:

java

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    // 分页插件:查第几页?每页几条?MP 帮你算!
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    // 乐观锁:防止小王和小李同时改商品价格,结果价格变成负数(别问,问就是血泪史)
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    return interceptor;
}

从此以后:

  • userService.page(new Page<>(1, 5)) → 直接返回分页数据!
  • 给 Product 加个 @Version 字段 → 更新时自动校验版本号,冲突直接失败!

java

public class Product {
    private Long id;
    private String name;
    private Integer price;

    @Version // 乐观锁核心!每次更新 version+1
    private Integer version;
}

🧪 测试结果:小王更新失败后重试,最终价格 120,老板满意,世界和平 ✌️


🧙 4. Mapper & Service:继承即战力!

Mapper 只需继承 BaseMapper<User>

java

public interface UserMapper extends BaseMapper<User> {}

Service 更狠:

java

public interface UserService extends IService<User> {}

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

然后你就能在 Controller 里疯狂调用:

java

@GetMapping("/list")
public List<User> list() {
    return userService.list(); // 查所有!
}

@PostMapping("/add")
public boolean add(@RequestBody User user) {
    return userService.save(user); // 新增!
}

@DeleteMapping("/delete/{id}")
public boolean delete(@PathVariable Long id) {
    return userService.removeById(id); // 逻辑删除!
}

@GetMapping("/page")
public Page<User> page(int pageNum, int pageSize) {
    return userService.page(new Page<>(pageNum, pageSize)); // 分页!
}

连 SQL 都不用写!
老板:“你这功能怎么这么快?”
我:“因为我站在巨人的肩膀上……而且巨人还帮我写了 CRUD。”


🎯 5. 条件查询?LambdaQueryWrapper 来了!

想查“名字带‘a’且年龄大于10”的用户?

java

LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(User::getName, "a")
       .ge(User::getAge, 10);
return userService.list(wrapper);

注意!这里用的是 User::getName,不是字符串 "name"
再也不怕手滑写错字段名导致半夜报警了!


🧪 6. 测试?MP 连测试都给你想好了!

java

@Test
void testOptimisticLock() {
    // 小李读价格 → 100
    // 小王读价格 → 100
    // 小李 +50 → 成功,version=1
    // 小王 -30 → 失败!因为 version 还是 0
    // 小王重试 → 成功!
    // 最终价格:120
}

这不比写文档清楚?


💬 结语:MP 不是偷懒,是高效!

MyBatis-Plus 并不是让你“不写代码”,而是把重复劳动交给框架,把创造力留给自己

  • 基础 CRUD?MP 给你。
  • 分页?MP 给你。
  • 逻辑删除?MP 给你。
  • 乐观锁?MP 给你。
  • 枚举映射?MP 给你。

你只需要专注业务逻辑,比如:

“用户注册时要不要发短信?”
“商品打折能不能叠加优惠券?”

而不是纠结:

“我的 XML 写错没?”
“分页的 limit offset 对不对?”


🎉 最后送大家一句话

“优秀的程序员,不是写最多的代码,而是让代码写得最少。”
—— 某个用了 MyBatis-Plus 后每天准时下班的人


项目源码已开源(假装),欢迎点赞、收藏、转发三连!
下次我们聊聊 MP + 多数据源 + 动态表名,让你的系统“灵活到飞起”!

👋 我是 周星星,一个正在努力不被 CRUD 压垮的程序员。
关注我,带你用最骚的姿势,写出最稳的代码!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐