ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MyBatis复杂SQL很灵活-自研ORM为何仍要保留SQL逃生口

MyBatis复杂SQL很灵活-自研ORM为何仍要保留SQL逃生口 MyBatis 复杂 SQL 很灵活自研 ORM 为何仍要保留 SQL 逃生口摘要MyBatis 的优势之一是复杂 SQL 可以明确交给开发者自研 ORM 不应为了“全自动”丢掉这种能力。MetaLite ORM 用BaseEntityDao覆盖单表高频 CRUD同时保留BaseSqlDao作为联表、窗口函数和数据库特性的 SQL 逃生口并对参数顺序、空结果和日志边界作出约束。ORM 设计经常走向两个极端所有查询都手写 SQL简单 CRUD 也充满重复字符串试图用一套 DSL 表达全部 SQL最后抽象比 SQL 本身更难理解。MetaLite 没有让Criteria无限膨胀而是保留两条数据访问通道高频单表操作走BaseEntityDao复杂查询走BaseSqlDao。一、BaseEntityDao 负责哪些高频问题BaseEntityJdbcDao根据实体元数据生成常见 SQL按主键或条件查询列表、排序、分页新增、批量新增按字段集合更新删除、计数和存在判断。字段名可通过方法引用解析值使用预编译参数。这部分价值不是“消灭 SQL”而是让重复率最高、最容易写错的单表操作使用统一路径。文章 014 已详细拆解这条生成链。二、哪些场景应该主动离开通用 CRUD遇到以下需求时继续扩展 Criteria 往往得不偿失多表关联和复杂子查询窗口函数、CTE、数据库专属函数一次返回非实体结构的统计报表精细控制执行计划或索引提示复杂批量 DML。BaseSqlDao为这些场景提供 insert、update、delete、count、单行和列表查询。它不是 ORM 失败后的补丁而是刻意保留的 SQL 逃生口。三、复杂 SQL 仍然复用哪些底座能力BaseSqlJdbcDao并非直接暴露一个裸JdbcTemplate。它仍然复用Dao指定的数据源组DbRouter的读写选择事务内强制读主库DAO 切面日志配置数据访问异常转换Map 到 Bean 的统一转换。因此业务虽然显式写 SQL连接池、主从、事务和异常治理仍在同一框架边界内。四、LinkedHashMap 的 key 并不是命名参数SQL 参数通过LinkedHashMapString, Object传入但实现只读取values()ListObjectvalueListnewArrayList(paramMap.values());这意味着 Map 的 key 只提高调用处可读性不会按名称绑定 SQL。真正决定第一个?对应哪个值的是插入顺序。如果调用者换成普通 HashMap或重构时调整 put 顺序SQL 仍能执行却可能把值绑定到错误字段。所以这条 API 的准确契约是“有顺序的参数列表”而不是“命名参数”。更稳妥的演进方向是显式 List、参数对象或 Spring NamedParameterJdbcTemplate。五、预编译参数和原始 SQL 不能混用单条 DML 和查询支持?占位符可以避免把用户输入直接拼进 SQL。但batchInsertBySql(ListString)接收的是完整 SQL 字符串列表没有参数绑定。只要这些字符串包含外部输入就重新引入 SQL 注入和转义风险。逃生口的原则应是结构可以显式写值仍尽量参数化。只有完全受控、没有外部数据的固定 SQL 才适合直接批量执行。六、findOne 当前有一个空结果边界findOneBySql先调用列表查询再直接执行getFirst()ListMapString,ObjectlistfindListBySql(sql,paramMap);returnlistnull?null:list.getFirst();JdbcTemplate.queryForList在没有记录时通常返回空列表而不是 null因此这里可能抛出空列表异常而不是返回 null。此外方法不会自动追加LIMIT 1调用者必须自己限制结果。文章示例不能把它描述成和findOneByCriteria完全相同的语义。七、SQL 日志为什么既有用又危险开启 DAO SQL 打印后JdbcHelper.formatSql会把占位值替换进日志文本排查路由和参数问题非常直观。但这也可能记录手机号、证件号、Token 或大字段。格式化日志仅用于展示并不是数据库最终执行文本也没有完整处理引号转义。生产环境应控制开关、字段和日志访问权限不能把“便于排查”变成敏感数据副本。八、GroupBy 已有聚合条件仍未完成公共 Query 支持GroupByJDBC 查询会生成GROUP BY。但AggCriteria当前仍是空类尚未形成 HAVING、聚合函数和结果映射能力。因此可以说“支持按字段分组”不能进一步宣传成“完整聚合 DSL”。复杂统计仍应走显式 SQL直到聚合抽象拥有真实实现和测试。九、逃生口也要有使用边界一个健康的数据访问层通常分三层高频单表 CRUD 使用类型安全抽象复杂查询使用显式、参数化 SQL极少数性能热点允许数据库专属优化并用测试固定行为。MetaLite 同时保留BaseEntityDao和BaseSqlDao避免为了“统一”而牺牲可读性。真正需要继续治理的是让 SQL 逃生口的参数、空结果和日志契约更明确。框架简介MetaLite 是面向企业生产环境的新一代 Java 微服务技术底座。系列文章重点分享代码背后的设计思路、技术取舍与工程实践。源码基线JDK 21、Spring Boot 3.2.9、Spring Cloud 2023.0.1、Spring Cloud Alibaba 2023.0.1.3具体组件版本以项目backend-bom为准。作者简介15 年 Spring 体系企业级开发经验专注于 Java 微服务架构、工程治理与生产实践。持续更新MetaLite 系列内容将持续更新围绕核心设计、源码链路、技术取舍与生产实践展开。欢迎关注作者及时获取后续内容。在线演示演示地址: https://admin.metalite.top/演示账号: guess演示密码: admin2026
返回列表