不建议运行期反射拼接mybatis xml sql,应使用@selectprovider、sqlbuilder或标签结合反射提取参数元数据生成动态sql,确保安全可控与可维护性。

不建议在运行期用反射动态组装 MyBatis 风格的 XML SQL 并直接 JDBC 执行——这不是 MyBatis 的设计意图,也违背其安全与可维护原则。真正可行且符合工程实践的方式,是利用 MyBatis 原生机制(如 <script></script>、@SelectProvider、SqlBuilder 或 XML 动态 SQL)配合反射做**参数/条件元数据驱动**,而非拼 XML 字符串。
用 @SelectProvider + 反射提取业务规则生成 SQL
MyBatis 提供 @SelectProvider 注解,允许你用 Java 代码动态构建 SQL。反射在此处用于读取业务对象的注解或字段状态,决定 where 条件、select 列表等:
- 定义业务实体类,用自定义注解标记可查询字段(如
@QueryField(like=true)) - 编写 Provider 类,在方法中通过反射遍历目标对象字段,检查注解和非空值,调用
SQL().SELECT(...).FROM(...).WHERE(...) - MyBatis 自动将返回的 SQL 字符串解析执行,仍走完整生命周期(参数绑定、类型转换、结果映射)
用 SqlBuilder / StringJoiner + 反射构造动态 WHERE 条件
避免手拼 XML 或裸 JDBC,改用 MyBatis 内置的 org.apache.ibatis.jdbc.SQL 工具类(或 JDK StringJoiner),结合反射判断条件有效性:
- 传入一个查询参数对象(如
UserQuery),反射获取所有 getter 方法 - 对每个 getter 调用,检查返回值是否非 null / 非空字符串 / 非默认值,再决定是否加入 WHERE 子句
- 示例:若
userQuery.getDeptId() != null,则追加.WHERE("dept_id = #{deptId}") - 最终返回的字符串交给
@SelectProvider或 XML 中的<script></script>使用
用 XML 中的 <script> 标签 + OGNL 表达式替代反射拼 SQL</script>
MyBatis 3.4+ 支持在 XML 中使用 <script></script> 标签,内部用 OGNL 解析对象属性,无需反射代码:
- Mapper XML 中写:
<script><select id="dynamicQuery">SELECT * FROM user WHERE 1=1<if test="deptId != null"> AND dept_id = #{deptId}</script> - MyBatis 运行时自动解析
#{deptId}对应参数对象的getDeptId()方法——本质也是反射调用,但由框架封装,安全可控 - 相比手动反射拼接,更易测试、支持缓存、防 SQL 注入、兼容分页插件
绕过 MyBatis 直接 JDBC 是高危操作,仅限极特殊场景
如果确实需要脱离 MyBatis 完全控制 SQL(如元数据驱动报表引擎),应封装为独立模块,且必须做到:
- SQL 模板预定义在配置或数据库中,禁止运行期拼接用户输入
- 所有参数严格走
PreparedStatement.setXXX(),绝不字符串拼接 - 表名/字段名若需动态,先白名单校验(如从
TableMeta表查出合法列名),再反射获取对应 getter 名称 - 执行后手动处理 ResultSet 映射(可用
BeanWrapper或ResultSetExtractor),不复用 MyBatis 的ResultMap
本质上,反射在这里的角色是“读取业务意图”,不是“生成 SQL 文本”。把动态性交给 MyBatis 的表达式引擎或 Provider 机制,才能兼顾灵活性与安全性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











