QueryWrapper - MyBatis-Plus的“查询条件构建器“
QueryWrapper就像餐厅的"点餐单",用来告诉数据库"我要查什么"
1. 基本概念
QueryWrapper<MealRecord>queryWrapper=new QueryWrapper<>();
类比:
- QueryWrapper = 点餐单
- <MealRecord> = 告诉服务员"我要查餐饮记录表"
- new QueryWrapper<>() = 拿一张新的点餐单
2. 实际使用
QueryWrapper<MealRecord>queryWrapper=new QueryWrapper<>();
queryWrapper.eq("record_date","2024-01-15"); //日期等于2024-01-15.eq("user_id",123); //用户ID等于123
MealRecord record =mealRecordMapper.selectOne(queryWrapper);
类比:
- 客人:"我要查2024-01-15的订单"
- 服务员:"好的,我记在点餐单上"
- 服务员:"还要查用户ID是123的订单"
- 服务员:"现在去厨房(数据库)找这个订单"
3. QueryWrapper的方法
queryWrapper.eq("字段名", 值) // 等于
queryWrapper.ne("字段名", 值) // 不等于
queryWrapper.gt("字段名", 值) // 大于
queryWrapper.lt("字段名", 值) // 小于
queryWrapper.like("字段名", 值) // 模糊查询
queryWrapper.in("字段名", 值列表) // 在列表中
queryWrapper.between("字段名", 开始值, 结束值) // 在范围内
4. 实际例子
//查询2024年1月的所有记录
QueryWrapepr<MealRecord>queryWrapper=new QueryWrapper<>();
queryWrapper.eq("user_id",123).apply("YEAR(record_date)={0}",2024) //年份等于2024.apply("MONTH(record_date)={0}",1); //月份等于1
List<MealRecord>records=mealRecordMapper.selectList(queryWrapper);
类比:
- 客人:"我要查2024年1月的所有订单"
- 服务员:"好的,我记在点餐单上"
- 服务员:"用户ID是123"
- 服务员:"年份是2024"
- 服务员:"月份是1月"
- 服务员:"现在去厨房找这些订单"
5. 为什么不用SQL?
传统SQL:
SELECT * FROM meal_records
WHERE user_id = 123
AND YEAR(record_date) = 2024
AND MONTH(record_date) = 1
QueryWrapper:
QueryWrapper<MealRecord>queryMapper=new QueryMapper<>();
queryWrapper.eq("user_id",123) .apply("YEAR(record_Date)={0}",2024).apply("MONTH(record_date)={0}",1);
优势:
- 类型安全:编译时检查字段名
- 链式调用:代码更简洁
- 防SQL注入:自动处理参数
6. 实际类比
餐厅点餐:
- 传统方式:客人直接说"我要查2024年1月,用户123的所有订单"
- QueryWrapper方式:客人说"我要查订单",然后一条条说条件:
- "用户ID是123"
- "年份是2024"
- "月份是1月"
QueryWrapper就是MyBatis-Plus提供的"智能点餐单",让查询条件更安全、更易读!
QueryWrapper 实际例子详解
让我用更生活化的方式解释这个例子:
1. 整体流程类比
QueryWrapper<MealRecord>queryWrapper =new QueryWrapper<>();
类比:客人走进餐厅,拿了一张"查询单"
queryWrapper.eq("record_date","2024-01-15");
类比:客人在查询单上写"我要查2024年1月15日的订单"
queryWeapper.eq("user_id",123);
类比:客人继续在查询单上写"用户ID是123"
MealRecord record=mealRecordMapper.selectOne(queryWrapper);
类比:客人把查询单递给服务员,服务员去厨房(数据库)找订单
2. 数据库实际执行
QueryWrapper会生成这样的SQL:
SELECT * FROM meal_records
WHERE record_date = '2024-01-15'
AND user_id = 123
3. 具体场景
场景:张三想查自己2024年1月15日的餐饮记录
步骤1:创建查询条件
QueryWrapper<MealRecord> queryWrapper=new QueryWrapper<>();
类比:张三拿了一张查询单
步骤2:添加第一个条件
queryWrapper.eq("record_date","2024-01-15");
类比:张三在查询单上写"日期:2024-01-15"
步骤3:添加第二个条件
queryWrapper.eq("user_id",123);
类比:张三继续写"用户ID:123"
步骤4:执行查询
MealRecord record=mealRecordMapper.selectOne(queryWrapper);
类比:张三把查询单给服务员,服务员去数据库找"2024-01-15日,用户123的订单"
4. 为什么需要两个条件?
问题:如果只有日期条件会怎样?
queryWrapper.eq("record_date", "2024-01-15");
结果:可能查到其他用户的订单!
解决:加上用户ID条件
queryWrapper.eq("record_date","2024-01-15").eq("user_id",123);
结果:只查到张三的订单
5. 实际数据示例
数据库中的记录:
id | user_id | record_date | breakfast | lunch | dinner
1 | 123 | 2024-01-15 | 15.00 | 25.00 | 30.00
2 | 456 | 2024-01-15 | 12.00 | 20.00 | 25.00
3 | 123 | 2024-01-16 | 18.00 | 22.00 | 28.00
查询结果
MealRecord record = // 只返回第1条记录(张三2024-01-15的订单)
6. 为什么用selectOne?
selectOne = 只返回一条记录
类比:服务员说"我找到了您要的订单,只有一条"
如果有多条记录:
- selectOne:返回第一条
- selectList:返回所有记录
7. 完整流程总结
- 创建查询单:new QueryWrapper<>()
- 写条件1:eq("record_date", "2024-01-15")
- 写条件2:eq("user_id", 123)
- 交给服务员:mealRecordMapper.selectOne(queryWrapper)
- 服务员去数据库找:执行SQL查询
- 返回结果:找到的订单记录
QueryWrapper就是一张"智能查询单",告诉数据库"我要查什么条件的数据"!