当前位置: 首页 > backend >正文

关于mybatis表关联查询和mybatis-Plus单表查询传入时间查询数据(走索引)

mysql 8.0字段数据类型为datetime

-- 为create_time字段创建普通索引
CREATE INDEX idx_test_create_time ON test (create_time);
 -- 为create_time字段类型为datetime`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

时间转换工具类

package com.boboboom.pro.api.utils;import io.micrometer.common.util.StringUtils;import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;public class DateRangeUtils {// region ====== 年月格式:yyyy-MM ======private static final String YEAR_MONTH_PATTERN = "yyyy-MM";private static final DateTimeFormatter YEAR_MONTH_FORMATTER = DateTimeFormatter.ofPattern(YEAR_MONTH_PATTERN);/*** 根据 yyyy-MM 格式字符串(如 "2024-06"),返回该月第一天 00:00:00 和最后一天 23:59:59 的 Date 对象** @param yearMonthStr 如 "2024-06"* @return MonthDateRange 包含 startDate 和 endDate*/public static MonthDateRange getDateRangeByYearMonth(String yearMonthStr) {if (StringUtils.isBlank(yearMonthStr)) {return null;}// 解析为 YearMonthYearMonth yearMonth = YearMonth.parse(yearMonthStr, YEAR_MONTH_FORMATTER);LocalDateTime startLdt = yearMonth.atDay(1).atStartOfDay();                    // 2024-06-01T00:00LocalDateTime endLdt = yearMonth.atEndOfMonth().atTime(LocalTime.MAX);         // 2024-06-30T23:59:59.999Date startDate = Date.from(startLdt.atZone(ZoneId.systemDefault()).toInstant());Date endDate = Date.from(endLdt.atZone(ZoneId.systemDefault()).toInstant());return new MonthDateRange(startDate, endDate);}// endregion// region ====== 年月日格式:yyyy-MM-dd ======private static final String YEAR_MONTH_DAY_PATTERN = "yyyy-MM-dd";private static final DateTimeFormatter YEAR_MONTH_DAY_FORMATTER = DateTimeFormatter.ofPattern(YEAR_MONTH_DAY_PATTERN);/*** 根据 yyyy-MM-dd 格式字符串(如 "2024-06-15"),返回当天 00:00:00 和 23:59:59 的 Date 对象** @param dayStr 如 "2024-06-15"* @return DayDateRange 包含当天的开始和结束时间*/public static DayDateRange getDateRangeByDay(String dayStr) {if (StringUtils.isBlank(dayStr)) {return null;}// 解析为 LocalDateLocalDate localDate = LocalDate.parse(dayStr, YEAR_MONTH_DAY_FORMATTER);LocalDateTime startLdt = localDate.atStartOfDay();                           // 2024-06-15T00:00LocalDateTime endLdt = localDate.atTime(LocalTime.MAX);                      // 2024-06-15T23:59:59.999Date startDate = Date.from(startLdt.atZone(ZoneId.systemDefault()).toInstant());Date endDate = Date.from(endLdt.atZone(ZoneId.systemDefault()).toInstant());return new DayDateRange(startDate, endDate);}// endregion// region ====== 返回值对象定义 ======/*** 用于封装 年月查询 的开始和结束时间*/public static class MonthDateRange {private final Date startDate;private final Date endDate;public MonthDateRange(Date startDate, Date endDate) {this.startDate = startDate;this.endDate = endDate;}public Date getStartDate() {return startDate;}public Date getEndDate() {return endDate;}}/*** 用于封装 日查询 的开始和结束时间*/public static class DayDateRange {private final Date startDate;private final Date endDate;public DayDateRange(Date startDate, Date endDate) {this.startDate = startDate;this.endDate = endDate;}public Date getStartDate() {return startDate;}public Date getEndDate() {return endDate;}}// endregion
}

实体类中时间入参

@Data
public class VipAccountQuery extends PageQuery {/*** 开始时间*/private String startTime;/*** 结束时间*/private String endTime;/*** 创建时间(不会走索引入参示例)*/private String createTime;}

ServiceImpl

//mybatis写法(多表关联)    @Overridepublic Pager<VipAccountDTO> pager(VipAccountQuery pageQuery, OptUserDTO optUserDTO) {Page<VipAccountDTO> page = pageQuery.toPage();Date startDate = null;Date endDate = null;if (StrUtil.isNotBlank(pageQuery.getStartTime())) {DateRangeUtils.DayDateRange startRange = DateRangeUtils.getDateRangeByDay(pageQuery.getStartTime());startDate = startRange != null ? startRange.getStartDate() : null;}if (StrUtil.isNotBlank(pageQuery.getEndTime())) {DateRangeUtils.DayDateRange endRange = DateRangeUtils.getDateRangeByDay(pageQuery.getEndTime());endDate = endRange != null ? endRange.getEndDate() : null;}// 执行分页查询Page<VipAccountDTO> resultPage = vipAccountMapper.selectPage(page, pageQuery, startDate, endDate,createTime);return PagerTool.toPager(resultPage, resultPage.getRecords());}//mybatis-plus写法(单表查询)@Overridepublic VipAccountMonthResult getFleetMonthlyIncomeAndExpense(VipAccountFlowParam pageQuery) {log.info("查询车队当月收支统计:{}", JSON.toJSONString(pageQuery));AssertUtil.notEmpty(pageQuery.getCreateTime(), "查询时间不能为空");AssertUtil.notNull(pageQuery.getVipAccountId(), "会员账户ID不能为空");Date startDate = Objects.requireNonNull(DateRangeUtils.getDateRangeByYearMonth(pageQuery.getCreateTime())).getStartDate();Date endDate = Objects.requireNonNull(DateRangeUtils.getDateRangeByYearMonth(pageQuery.getCreateTime())).getEndDate();Long vipAccountId = pageQuery.getVipAccountId();List<VipAccountFlowEntity> vipAccountFlowEntities = vipAccountFlowMapper.selectList(new LambdaQueryWrapper<>(VipAccountFlowEntity.class).eq(VipAccountFlowEntity::getAccountVipId, vipAccountId).ge(VipAccountFlowEntity::getCreateTime, startDate).lt(VipAccountFlowEntity::getCreateTime, endDate));System.out.println(JSON.toJSONString(vipAccountFlowEntities));//  return vipAccountFlowMapper.getFleetMonthlyIncomeAndExpense(startDate, endDate,vipAccountId);}

Mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.boboboom.pro.api.system.vipaccount.param.VipAccountParam;
import com.boboboom.pro.module.system.bizaccount.model.dto.VipAccountDTO;
import com.boboboom.pro.module.system.bizaccount.model.entity.VipAccountEntity;
import com.boboboom.pro.module.system.bizaccount.model.param.VipAccountQuery;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.math.BigDecimal;
import java.util.Date;@Mapper
public interface VipAccountMapper extends BaseMapper<VipAccountEntity> {Page<VipAccountDTO> selectPage(Page<VipAccountDTO> page,@Param("pageQuery") VipAccountQuery pageQuery,@Param("startTime") Date startTime,@Param("endTime") Date endTime,@Param("createTime") Date createTime);}

Mapper.xml

    
<!-- 多表关联查询使用 -->
<select id="selectPage" resultType="com.model.dto.VipAccountDTO">SELECT*FROMtest1 t1INNER JOIN test2 t2 ON t1.id = t2.idWHERE 1=1<if test="startTime != null">AND t1.create_time >= #{startTime}</if><if test="endTime != null">AND t1.create_time &lt;= #{endTime}</if>ORDER BY t1.create_time DESC</select>

下面是不会走索引的查询

        <if test="pageQuery.createTime != null">AND DATE_FORMAT(t1.create_time, '%Y-%m') = #{pageQuery.createTime}</if>

最终sql语句(走索引)

SELECT*
FROMtest t1
WHEREt1.create_time >= '2025-08-01 00:00:00.0'AND t1.create_time <= '2025-08-31 23:59:59.999';

PS:如果查询范围过大,全表扫描更高效
MySQL 优化器会判断:如果查询的记录数占表总记录数的比例较高(通常超过 20%-30%),全表扫描(ALL)可能比走索引更快(因为索引需要额外的磁盘 I/O 和回表操作)。
例如:如果 8 月份的数据占表中大部分记录,优化器可能直接选择全表扫描。

最终sql语句(不走索引)

SELECT*
FROMtest t1
WHEREDATE_FORMAT(t1.create_time, '%Y-%m') = '2025-08'

索引命中级别type:访问类型(最重要的参数之一)

表示 MySQL 访问表中数据的方式,反映查询效率,从优到差排序

  • system:表中只有一行数据(如系统表),效率最高。
  • const:通过主键或唯一索引查询,最多返回一行,如 WHERE id = 1
  • eq_ref:多表连接时,被连接表通过主键或唯一索引匹配,每行只匹配一次(如 JOIN 中 ON 条件使用主键)。
  • ref:非唯一索引的等值查询,可能返回多行(如普通索引的 WHERE name = 'xxx')。
  • range:索引范围查询(如 >、<、BETWEEN、IN)。
  • index:扫描整个索引树(比 ALL 好,因为索引通常比数据小)。
  • ALL:全表扫描(效率最低,需优化)。
http://www.xdnf.cn/news/18170.html

相关文章:

  • Linux Namespace 隔离的“暗面”——故障排查、认知误区与演进蓝图
  • CVPR 2025 | 具身智能 | HOLODECK:一句话召唤3D世界,智能体的“元宇宙练功房”来了
  • 【HTML】3D动态凯旋门
  • 通过C#上位机串口写入和读取浮点数到stm32的片内flash实战4(通过串口下发AD9833设置值并在上位机显示波形曲线)
  • “你不干有的是AI干”,提示词中的“情感化提示”
  • 如何在 Ubuntu Linux 上安装 RPM 软件包
  • 【SQL优化案例】统计信息缺失
  • Vercel v0 iOS版重磅发布:AI驱动的移动开发新篇章
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘paramiko’问题
  • C++入门自学Day14-- Stack和Queue的自实现(适配器)
  • Java高级面试实战:Spring Boot微服务与Redis缓存整合案例解析
  • “R语言+遥感”的水环境综合评价方法实践技术应用
  • Centos7物理安装 Redis8.2.0
  • 【GNSS定位原理及算法杂记6】​​​​​​PPP(精密单点定位)原理,RTK/PPK/PPP区别讨论
  • 【部署相关】DockerKuberbetes常用命令大全(速查+解释)
  • 孩子王披露半年报:多数据持续增长,全年预期增强
  • git仓库和分支的关系
  • Linux GPIO子系统中开漏模式软件仿真机制的深度分析
  • 【深度学习计算性能】06:多GPU的简洁实现
  • 树状数组/差分数组/线段树/莫队算法介绍
  • 政务窗口服务满意度调查:服务型政府建设赋能方案(北京市场调研)
  • 2025年12大AI测试自动化工具
  • 电子电气架构 --- 软件项目风险管理
  • 「内力探查术」:用 Instruments 勘破 SwiftUI 卡顿迷局
  • Android Coil 3拦截器Interceptor计算单次请求耗时,Kotlin
  • 软件测试-Selenium学习笔记
  • Node.js 在 Windows Server 上的离线部署方案
  • Linux系统安全补丁管理与自动化部署研究与实现(LW+源码+讲解+部署)
  • 2.Kotlin 集合 List 所有方法
  • 云原生俱乐部-mysql知识点归纳(3)