建站案例

写了 10 年 MyBatis,一直以为“去 XML”=写注解,直到看到了这个项目

发表日期:2026-04-13

一直对 MyBatis 有个刻板印象:Mapper 接口负责声明方法,Mapper.xml 负责写 SQL

改条件就去 XML 里 ,调参数就切换不同文件,从刚开始学到现在用了很久,熟悉得不能再熟悉。

直到最近看到一个项目:我把 resources/mapper 翻了个底朝天,愣是没找到一份 XML。

我第一反应:

“这项目肯定是全用 @Select 之类的注解硬写 SQL 了吧。”

结果打开 Mapper:我人傻了。

1)去 XML:@Select

单表按主键查,注解很舒服:

python体验AI代码助手代码解读复制代码@Select("select * from tb_user where id = #{id}")UserDO selectById(Long id);


但一旦要动态条件,很多人会写成这种:

less体验AI代码助手代码解读复制代码@Select("" +        "select * from tb_user " +        "" +        "   and name like concat('%', #{name}, '%') " +        "   and age >= #{age} " +        "" +        "")List list(UserQuery req);


这么些的体验基本是:

  • • 字符串拼接看得眼疼

  • • 没有 SQL 高亮、格式化也很难受

  • • 复杂一点直接维护灾难

所以绝大多数团队最终都会回到 XML——至少 XML 里写动态 SQL 还能接受。

2)去 XML:@SelectProvider

这个项目里 Mapper 长这样:

python体验AI代码助手代码解读复制代码@SelectProvider(type = UserSqlProvider.class, method = "selectByCondition")List selectByCondition(UserQuery req);


我当时心里一句话:

“Provider?这是什么东东?”

点进 UserSqlProvider,看到的是这种代码:

scss体验AI代码助手代码解读复制代码public class UserSqlProvider {  public String selectByCondition(UserQuery req) {    return new SQL() {{      SELECT("id, name, age, status, create_time");      FROM("tb_user");      if (req.getName() != null && !req.getName().isBlank()) {        WHERE("name like concat('%', #{name}, '%')");      }      if (req.getMinAge() != null) {        WHERE("age >= #{minAge}");      }      if (req.getStatus() != null) {        WHERE("status = #{status}");      }      ORDER_BY("create_time desc");    }}.toString();  }}


当时我有点惊讶: SQL()SELECT()WHERE() 这些不是自定义工具类,而是 MyBatis 自带的 SQL Builder

这类写法的本质是:

  • XML 动态 SQL 的能力不变

  • • 但“拼 SQL 的载体”从 XML 变成 Java Provider 方法

  • • 最终 MyBatis 仍然执行一段 SQL 字符串(只是这段字符串由 builder 组装出来)

文章来源网络收集