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

别再写硬编码了!MyBatis-Plus的apply方法,这样用才安全又灵活(附日期查询实战)

别再写硬编码了!MyBatis-Plus的apply方法,这样用才安全又灵活(附日期查询实战)

在Java开发中,动态SQL拼接是个绕不开的话题。记得刚入行时,我为了赶进度直接在代码里拼接SQL字符串,结果上线后遭遇了SQL注入攻击,差点酿成大祸。那次教训让我深刻认识到:字符串拼接不是编程,而是埋雷。今天我们就来聊聊MyBatis-Plus中那个被低估的apply方法——它可能是你代码安全最后的防线。

1. 为什么我们需要告别硬编码

硬编码SQL就像把数据库密码写在代码注释里——看似方便,实则危险。我曾见过一个经典案例:开发者为了查询某天的用户数据,直接写出了这样的代码:

String sql = "date_format(birthday,'%Y-%m-%d') = '" + date + "'"; wrapper.apply(sql);

date参数来自用户输入时,攻击者只需传入' OR '1'='1这样的值,就能轻松获取全表数据。而使用参数化替换的apply方法后:

wrapper.apply("date_format(birthday,'%Y-%m-%d') = {0}", date);

MyBatis-Plus会自动将参数预处理为预编译语句,从根本上杜绝注入风险。这两种方式的底层SQL对比如下:

方式生成SQL示例安全性
硬编码date_format(birthday,'%Y-%m-%d') = '2023-01-01'高危
参数化date_format(birthday,'%Y-%m-%d') = ?安全

2. apply方法的实战应用技巧

2.1 日期处理的正确姿势

日期查询是最容易踩坑的场景。假设我们需要查询2023年国庆节当天的用户:

// 错误示范(直接拼接) wrapper.apply("DATE(birthday) = '2023-10-01'"); // 正确做法(参数化) wrapper.apply("DATE(birthday) = {0}", LocalDate.of(2023, 10, 1));

更复杂的场景比如查询最近30天活跃用户:

wrapper.apply("last_login_time BETWEEN {0} AND {1}", LocalDateTime.now().minusDays(30), LocalDateTime.now());

2.2 动态条件组合的艺术

applycondition参数让动态SQL变得优雅。比如根据权限过滤数据:

boolean isAdmin = getCurrentUser().isAdmin(); wrapper.apply(!isAdmin, "department_id = {0}", userDeptId);

isAdmin为false时才会添加部门过滤条件。这种写法比在service层写if判断更清晰。

3. 高级应用:数据库函数安全调用

3.1 字符串函数的安全使用

字符串拼接同样需要防范注入。比如模糊查询用户名:

// 危险方式 wrapper.apply("CONCAT('%', '" + name + "', '%')"); // 安全方式 wrapper.apply("CONCAT('%', {0}, '%')", name);

3.2 JSON字段查询方案

现在很多项目使用JSON字段存储扩展属性。假设我们要查询profile字段中address.city为北京的用户:

wrapper.apply("JSON_EXTRACT(profile, '$.address.city') = {0}", "北京");

不同数据库的JSON函数差异较大,但参数化原则不变:

数据库JSON查询函数示例
MySQLJSON_EXTRACTJSON_EXTRACT(column, '$.path')
PostgreSQL->>column->>'path'
OracleJSON_VALUEJSON_VALUE(column, '$.path')

4. 性能优化与最佳实践

4.1 索引使用注意事项

虽然apply很强大,但滥用会影响索引效率。比如这样的写法:

wrapper.apply("YEAR(create_time) = {0}", 2023);

会导致MySQL无法使用create_time上的索引。更好的方式是:

wrapper.between("create_time", LocalDateTime.of(2023, 1, 1, 0, 0), LocalDateTime.of(2023, 12, 31, 23, 59));

4.2 复杂查询的拆解策略

遇到特别复杂的SQL时,不要试图用一个apply解决所有问题。比如多表关联查询:

// 不推荐 wrapper.apply("EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.status = {0})", 1); // 推荐使用join或分开查询 wrapper.inSql("id", "SELECT user_id FROM orders WHERE status = 1");

实际项目中,我发现将复杂逻辑拆分为多个简单查询往往性能更好,代码也更易维护。

http://www.jsqmd.com/news/683728/

相关文章:

  • 1篇5章2节:macOS 必备开源包管理器 Homebrew
  • 生化危机8修改器 风灵月影 支持最新版本
  • Element UI 表格合并踩坑记:从官网示例到真实业务场景的完整避坑指南
  • ROS+Catkin项目如何正确生成compile_commands.json?让clangd在VSCode里精准补全
  • Python 工程化开发与性能优化实践
  • 别再到处找数据了!手把手教你从三大GWAS数据库(IEU、MiBioGen、FinnGen)一键下载与清洗
  • 光学设计避坑指南:反射棱镜选型、展开与光轴计算的3个关键步骤
  • 前端性能优化实战:用FormData和axios拦截器改造el-upload,轻松合并上传请求
  • 告别内核编译:手把手教你用Linux configfs动态配置USB音频设备(UAC2.0实战)
  • 麒麟系统更新后输入法消失?别慌,一个终端命令帮你找回(附fcitx修复详解)
  • 选择电容的额定电压,核心依据
  • 告别手动涂色!LaTeX进阶技巧:用xpatch动态控制特定参考文献的样式(以颜色为例)
  • S04|子代理:给 Agent 开 “独立小房间”,上下文不乱、主线不飘
  • OFA-VE部署教程:使用Poetry管理依赖,构建可复现的Python3.11环境
  • 告别碎片化:B站缓存视频一键合并的安卓神器
  • 告别软件调参烦恼:用PSpice手把手教你搭建一个“傻瓜式”硬件PID控制器(附完整电路图)
  • p70 S6激酶重组兔单抗能否解析mTOR信号枢纽?
  • 别再用‘abandon’背单词了!我用这3个App搞定英语词汇分层记忆(附实操截图)
  • 手把手教你用Vivado为ZCU102配置PS端外设:以太网、USB、PCIe一个都不少
  • Brain | 大脑的“隐秘连接”:神经可塑性的连接组储备?
  • visual studio上创建linux程序的新方法
  • 2026年3月热门的伸缩篷厂家推荐,小区车棚/景观棚/充电桩棚/电动推拉棚/膜结构/膜结构车棚,伸缩篷生产厂家哪家可靠 - 品牌推荐师
  • 别再傻傻分不清!5分钟看懂N沟道和P沟道MOS管的型号命名规律(附快速识别表)
  • 避开 Proteus 仿真 IIC 的 3 个常见坑:以 AT89C52 驱动 AT24C02 为例
  • STM32F4实战:用HAL库+FreeRTOS+FreeModbus搭建工业级从机,附完整源码和避坑指南
  • 从POI源码看CellStyle限制:为什么你的EasyExcel导出会报64000样式错误?
  • 测试时数据增强(TTA)技术解析与应用实践
  • 鸿蒙App接入“龙虾”智能体:从0到1打造下一代AI原生应用(附完整代码)
  • 好题集 (12) - LG P4119 [Ynoi2018] 未来日记
  • 别再只用Nginx了!用Squid在Windows搭建高性能HTTP缓存代理实战