好久没更新文章了,是在有些堕落了,最近项目有些忙,加班有些多,给自己提升和思考总结的时间少了些,昨晚刚好有空,整理了下之前的笔记,发现了项目使用中记录的一些MybatisPlus
的总结,这里重新整理下。
建议1:使用MybatisPlus生成实体类的时候,设置entityColumnConstant=true
将字段常量一起生成。
建议2:新建一个自己的业务实体类XxBaseService
继承MyBatisPlus
自带的com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
,好处是在XxBaseService
中你可以自己扩展一些基础方法
建议3:通过ServiceImpl
中的QueryChainWrapper<T> query()
和UpdateChainWrapper<T> update()
进行数据的CRUD
。该建议同建议1进行搭配。
之所以不使用
LambdaQueryChainWrapper<T> lambdaQuery()
- 一是因为生成的字段常量的方式性能更好,少了一层反射。
- 二是字符串形式的
select
支持自定义的列,比如select(SignHospital.FROM_HOS_NAME,"date_format(sign_date,'%Y-%m-%d') as sign_date2")
- 三是因为其不支持
Kotlin
,我们服务端50%的代码都是Kotlin了。之所以不适用传统的方式,那是因为传统的方式不支持链式写法,不够优美。
建议4:开发阶段通过p6spy
打印SQL
,方便排除问题,可以参考官网:执行 SQL 分析打印 | MyBatis-Plus
建议5:通过select("列1","列2")
来筛选需要的内容,特别是字段列很多,单你仅仅需要1-2个的时候。
查询的时候,带有or
的时候,可以先通过and
引导,然后在条件中写or
案例1:
val resPage = query()
.gt(pageReqHos.beginSignDate != null, SignHospital.SIGN_DATE, pageReqHos.beginSignDate)
.lt(pageReqHos.endSignDate != null, SignHospital.SIGN_DATE, pageReqHos.endSignDate)
.and(!pageReqHos.hosName.isNullOrBlank()) {
it.like(SignHospital.FROM_HOS_NAME, pageReqHos.hosName)
.or()
.like(SignHospital.TO_HOS_NAME, pageReqHos.hosName)
}.page(page)
案例2:
List<UserCore> list = super.lambdaQuery()
.select(UserCore::getId, UserCore::getHospitalId, UserCore::getHospitalName)
.eq(UserCore::getAsDelete, 0)
.and(p -> p.eq(UserCore::getHospitalName, hosName).or().eq(UserCore::getHospitalId, hosId))
.last(" limit 1000").list();
first用的很少,不过last用的很多,他会在where
条件后拼接内容,比如业务中进行查询的时候,很多时候都建议带上一个超过正常预期范围2倍的limit 2n
,这样可以有效的避免查询出非常多内容后出现的OOM
。
比如查询一个班级的学生,业务已经很明确的知晓了一个班级最大60名学生,此时你作为防御机制,可以在查询的时候,跟上limit 120
,可以避免你手抽的时候没有写上where 班级id=1
导致的一些类似问题。
query().eq(MxUser.GROUP_ID,'123').last("limit 100")
对应的SQL只能查出最大的100名用户,这里请注意你的阈值,不要同业务冲突。
SELECT * FROM mx_user WHERE group_id='123' LIMIT 100
可以利用apply
或者inSql
来完成部分内容。
同理你的Update
其实也可以带上LIMIT
的,这也是一个防御策略。
一个很典型的需求就是在查询的时候,需要引入SQL的函数,比如在一张签约表中,查询2021年签约的医院。
query().apply("date_format(sign_date,'%Y')={0}","2022").list()
对应出的sql
SELECT * FROM sign_hos WHERE date_format(sign_date,'%Y')='2022'
比如学生表中,需要查询的是在某些班级的学生,此时加入某些班级
以及确定的情况下,可以使用in
,但是假如这些班级不确定,而是通过另外的sql语句进行查询出来的,此时推荐使用inSql
query().inSql("c_id","SELECT id FROM spec_cls WHERE type=1").list()
对应的sql
SELECT * FROM mx_user WHERE c_id IN
(
SELECT id FROM spec_cls WHERE type=1
)
我对这个用的少,大概的意思是就是括号包装下
其实MybatisPlus
带有更多的高阶用法,不过我个人建议不必太过执着的一定要通过API的形式完成复杂的SQL
,直接在XML
中书写可能也是一个非常的方法,请根据自己团队对MP
的熟悉程度做出权衡。