03_Mybatis-Plus LambadaQueryWrapper 表达式爆空指针异常

03_MyBatis-Plus LambdaQueryWrapper 爆出空指针异常的坑点分析

❓ 场景描述

来看一段常见的 MyBatis-Plus 查询写法,是否存在问题?

Page<VideoInfoVo> videoInfoVosPage = videoMapper.selectPage(page, new LambdaQueryWrapper<VideoInfoVo>()
    .eq(videoAdtReq.getUserId() != null, VideoInfoVo::getUserId, videoAdtReq.getUserId())
    .ge(videoAdtReq.getStartTime() != null, VideoInfoVo::getUpdateTime, videoAdtReq.getStartTime().atStartOfDay())
    .le(videoAdtReq.getEndTime() != null, VideoInfoVo::getUpdateTime, videoAdtReq.getEndTime().atTime(LocalTime.MAX))
);

问题分析:会爆出 NullPointerException!

错误点在哪?

.ge(videoAdtReq.getStartTime() != null, VideoInfoVo::getUpdateTime, videoAdtReq.getStartTime().atStartOfDay())
.le(videoAdtReq.getEndTime() != null, VideoInfoVo::getUpdateTime, videoAdtReq.getEndTime().atTime(LocalTime.MAX))

表面上看已经做了非空判断,似乎没有问题,但实际上,这样写仍然可能爆出 NullPointerException


关键误区:Java 的参数求值顺序

Java 会在调用方法前,先对所有参数进行求值,然后再把这些值传给方法体。

所以即使你写了:

videoAdtReq.getStartTime() != null

Java 仍然会执行

videoAdtReq.getStartTime().atStartOfDay()

如果 getStartTime() 返回的是 null,那 .atStartOfDay() 立即爆 NPE


✅ 正确写法:提前提取变量,避免链式空指针

LocalDateTime start = null;
LocalDateTime end = null;

if (videoAdtReq.getStartTime() != null) {
    start = videoAdtReq.getStartTime().atStartOfDay();
}
if (videoAdtReq.getEndTime() != null) {
    end = videoAdtReq.getEndTime().atTime(LocalTime.MAX);
}

Page<VideoInfoVo> videoInfoVosPage = videoMapper.selectPage(page, new LambdaQueryWrapper<VideoInfoVo>()
    .eq(videoAdtReq.getUserId() != null, VideoInfoVo::getUserId, videoAdtReq.getUserId())
    .ge(start != null, VideoInfoVo::getUpdateTime, start)
    .le(end != null, VideoInfoVo::getUpdateTime, end)
);

小结 Tips

写法 是否安全 原因
.eq(cond, field, value) ✅ 安全 不涉及链式 null 调用
.ge(cond, field, value.atStartOfDay()) ❌ 危险 即使 cond == falsevalue.atStartOfDay() 已执行

建议

  • 所有可能为 null 的链式操作都要提前拆解;
  • 不要在 .ge().le().like() 等条件方法内部写链式 null 调用
  • 最好在写查询条件前,先准备好转换后的数据变量。

你可能感兴趣的:(【后端开发】Java,碎碎念,mybatis)