MyBatis动态查询技术疑问:SQL Builder与结果映射等问题
MyBatis 动态查询相关问题解答
针对你用Java 8、MyBatis 3.4.6搭配Postgres 9.6实现自定义动态查询时遇到的三个问题,结合实际使用经验给你逐一解答:
1. 是否必须显式配置@Results及每个@Result,能否直接使用Java模型类?
答案是不一定需要显式配置@Results,分两种情况来看:
- 如果你的Java模型类字段名和Postgres数据库列名遵循驼峰-下划线对应规则(比如Java类的
preIngestId对应数据库的pre_ingest_id),只需要在MyBatis配置中开启驼峰命名自动映射:
开启后,MyBatis会自动完成字段与列名的映射,直接返回Java模型类即可,无需手动配置@Results。<settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> - 你尝试用
@ResultMap("mycompany.model.PreIngest")未生效,是因为@ResultMap的参数并不是直接指向Java模型类,而是要指向已经定义好的ResultMap的ID:要么是在Mapper接口中用@Results注解定义并指定id属性,要么是在XML映射文件中定义的<resultMap>的id。比如:@Results(id = "preIngestResultMap", value = { @Result(column = "pre_ingest_id", property = "preIngestId"), // 其他字段映射... }) @SelectProvider(...) List<PreIngest> selectPreIngests(...); // 后续方法可以复用这个ResultMap @ResultMap("preIngestResultMap") @Select("SELECT * FROM pre_ingest WHERE id = #{id}") PreIngest getById(Long id);
2. SQL Builder中final参数无法访问,是否需删除@Param?SQL Builder是否无需@SelectProvider调用?
首先明确两个关键点:
- SQL Builder必须配合@SelectProvider使用:MyBatis需要通过
@SelectProvider指定生成SQL的类和方法,才能在调用Mapper接口方法时自动触发SQL的构建,不存在“无需@SelectProvider调用”的情况,你没有混用方案,只是参数处理的方式不对。 - 关于final参数和@Param的问题:
如果你的Mapper接口方法用了@Param注解,那么在SQL Builder的方法中,有两种方式获取参数:- 方法参数接收
Map<String, Object>,通过键名(即@Param指定的名称)获取参数值,此时参数加不加final不影响:public String selectPreIngestsSQLBuilder(final Map<String, Object> params) { Integer status = (Integer) params.get("status"); return new SQL() {{ SELECT("*"); FROM("pre_ingest"); if (status != null) { WHERE("status = #{status}"); } }}.toString(); } - 开启Java编译的
-parameters选项(Java 8及以上支持),SQL Builder方法可以直接用和@Param一致的参数名接收,加final也完全可以访问:public String selectPreIngestsSQLBuilder(@Param("status") final Integer status) { return new SQL() {{ SELECT("*"); FROM("pre_ingest"); if (status != null) { WHERE("status = #{status}"); } }}.toString(); }
- 方法参数接收
3. 三种动态查询方式的选择场景,以及SQL Builder文档无调用说明的原因
何时优先选择XML动态SQL而非SQL Builder?
两种方式各有优劣,优先选XML动态SQL的场景包括:
- SQL逻辑复杂:比如包含多层嵌套的条件判断、
IN子句批量查询、多表关联查询、动态排序等,XML的<if>、<choose>、<foreach>等标签语法更直观,可读性和维护性更强,熟悉SQL的开发或DBA也更容易理解和优化。 - 需要复用SQL片段:XML的
<include>标签可以轻松复用常用的SQL片段(比如字段列表、通用条件),避免重复代码。 - 团队习惯:如果团队更倾向于把SQL和Java代码分离,XML方式更符合传统的分层架构思想,便于统一管理SQL。
SQL Builder的优势则是适合喜欢在Java代码中统一处理逻辑的场景,比如SQL逻辑和Java业务逻辑紧密绑定,或者团队偏好纯Java配置无XML的项目结构。
为什么SQL Builder文档无调用说明?
其实SQL Builder的“调用”就是通过@SelectProvider关联Mapper接口方法来实现的:当你调用Mapper接口中标记了@SelectProvider的方法时,MyBatis会自动调用指定的SQL Builder方法生成SQL,然后执行查询返回结果。文档之所以没单独说明“调用方法”,是因为它默认你已经掌握了@SelectProvider的基本用法,而SQL Builder本身只是用来生成SQL字符串的工具,不需要单独调用。
内容的提问来源于stack exchange,提问作者Fjordo




