You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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配置中开启驼峰命名自动映射:
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    开启后,MyBatis会自动完成字段与列名的映射,直接返回Java模型类即可,无需手动配置@Results。
  • 你尝试用@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的方法中,有两种方式获取参数:
    1. 方法参数接收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();
      }
      
    2. 开启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();
      }
      
    你遇到的“添加final后无法访问”大概率是参数传递的写法错误,不需要删除@Param,调整SQL Builder方法的参数接收方式即可。

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

火山引擎 最新活动