⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7156428078061895710 「糊涂码」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

前言

MP 从出现就一直有争议 感觉一直 都存在两种声音

like:

很方便啊 通过函数自动拼接Sql 不需要去XML 再去使用标签 之前一分钟写好的Sql 现在一秒钟就能写好 简直不要太方便

dislike:

侵入Service层 不好维护 可读性差 代码耦合 效率不行 sql优化比较难

之前也有前辈说少用MP 理由就是不好维护 但是这个东西真的是方便 只要不是强制不让用 就还是会去使用 存在集合里 最近也确实有一些体会 就从两个角度去看一下MP

优点

操作简洁

就从我们编码中最常用的增删改查去说

按照我们之前去使用Mybatis的喜欢我们就要去建立一个XML文件 去编写Sql语句 算是半自动 我们可以直接去操控Sql语句 但是会比较麻烦 很多简单的数据查询我们都要去写一个标签 感觉这种没有意义的操作还是比较烦的 那么MP里面怎么实现

第一种: 最简单我们就是直接去使用提供的方法 我们非常简单就能做到这些操作 但是这个就有一个问题

nodeMapper.selectById(1);
nodeMapper.deleteById(2);
nodeMapper.updateById(new Node());
nodeMapper.insert(new Node());

维护性差 以查询为例 这个默认提供的方法都是查询所有字段我们都知道在编写Sql的时候第一条优化准则就是不要使用Select * 因为这种写法是很Low

这个就是上面selectById执行的结果

SELECT Id,name,pid FROM node WHERE Id=?

这种Sql 肯定是不好的所以我们在使用MP的时候尽量不要去使用自带的快捷查询 我们可以去使用它里面的构造器

nodeMapper.selectOne(new QueryWrapper<Node>().eq("id",1).select("id"));

这汇总写法 我们可以通过后面的select() 去指定我们需要查询的字段 算是解决上面那个问题吗 但是这个就完事了吗? 这还有一个问题

我们在开发中经常会说一个叫魔法值的东西

//这个就是魔法值 
if ("变成派大星".equals(node.getName())){
System.out.println("魔法值");
}

之所以不要多用魔法值就是为了后期维护 我们建议使用枚举 或者建一个常量类 通过Static final修饰

上面那段代码是不是也有同样问题 "id"算不算魔法值呢 这种构造器产生的问题就是 不好维护

假设 我们的这Node类是高度使用的 我们到处都在写

nodeMapper.selectOne(new QueryWrapper<Node>().eq("id",1).select("id"));

刚开始没事 我们乐呵呵的 但是一旦我去修改Id 的字段名怎么办

我修改成test(数据库同步修改) 现在这个实体类中没有这个字段 我们再去看我们的代码

没有什么反应 没有给我提示报错 我这个时候去运行怎么办 我要一个个去找这个错误吗 这明显很费时间

这个确实是一个问题 但是也是可以解决的

Node node = nodeMapper.selectOne(new LambdaQueryWrapper<Node>().eq(Node::getId, 1).select(Node::getId));

上面这种代码就可以去解决这个问题 我们在使用的时候可以多用这个东西

一旦修改字段就会立马报错

但是 这就万事大吉了吗 NO No NO 我们要是处理稍微复杂的语句怎么办? 比如如我们字段求和 这个LambdaQueryWrapper还是存在限制的

如果我们想实现这种 怎么去做呢

select SUM(price_count) from  bla_order_data LIMIT 100

首先这种写法肯定是不太行的 编译不通过

除非去使用QueryWrapper

还有就是分页查询

// 条件查询
LambdaQueryWrapper<UserInfo> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(UserInfo::getAge, 20);
// 分页对象
Page<UserInfo> queryPage = new Page<>(page, limit);
// 分页查询
IPage<UserInfo> iPage = userInfoMapper.selectPage(queryPage , queryWrapper);
// 数据总数
Long total = iPage.getTotal();
// 集合数据
List<UserInfo> list = iPage.getRecords();

这个还是非常简单的

简单总结

MP 在做一些简单的单表查询可以去使用但是对于一些复杂的SQl操作还是不要用

1、SQL侵入Service 的问题我们可以仿照 Mybatis 建一个专门存放 MP查询的包

2、关于维护性 我们可以尽量去使用 LambdaQueryWrapper 去构造

3、MP是有内置的主键生成策略

4、内置分页插件:基于 Mybatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通List查询。

缺点

我就说一个最大的缺点就是对于复杂Sql 的操作性很不舒服 比如我们去多表查询 你怎么去写呢

看一个例子

就是通过 @Select 注解将Mp的查询条件嵌入进去${ew.customSqlSegment}

咱就是一整个大问号 联表老老实实去写XML吧 这种真的不要去用 太丑了

总结

没有过多的东西 基本都是最近看到的东西

1、复杂语句不推荐使用MP 能用最好也别用 可读性差 难维护 使用刚开始没感觉 后期业务扩充 真的恶心的

2、可以使用MP中的分页 比较舒服 逐渐生成策略也舒服

3、尽量不要去使用MP中自带的selectById 等全表查询的方法

4、尽量使用LambdaQueryWrapper的书写形式 至少比较好维护

5、简单重复Sql 可以用MP。复杂SQL不要用

完结有想到的会补充各位同僚有其他意见可以评论区见 会补充修正

文章目录
  1. 1. 前言
  2. 2. 优点
    1. 2.1. 操作简洁
  3. 3. 简单总结
    1. 3.1. 缺点
  4. 4. 总结