一直对 MyBatis 有个刻板印象:Mapper 接口负责声明方法,Mapper.xml 负责写 SQL。
改条件就去 XML 里 ,调参数就切换不同文件,从刚开始学到现在用了很久,熟悉得不能再熟悉。
直到最近看到一个项目:我把 resources/mapper 翻了个底朝天,愣是没找到一份 XML。
我第一反应:
“这项目肯定是全用
@Select之类的注解硬写 SQL 了吧。”
结果打开 Mapper:我人傻了。
单表按主键查,注解很舒服:
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 还能接受。
这个项目里 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 组装出来)