MyBatis 的 Mapper 接口 default 方法不能写 SQL,因其仅为普通 Java 代码,未被 MyBatis 解析注册为映射语句;SQL 只能写在抽象方法的注解或 XML 中,default 方法仅可调用已有映射方法作逻辑复用。

MyBatis 的 Mapper 接口本身不能直接在接口的 default 方法里写 SQL。Default 方法是 Java 语言特性,运行在 JVM 中,而 MyBatis 的 SQL 执行依赖于 XML 映射文件、注解(@Select 等)或 SqlSession 手动调用——这些都和接口方法的字节码无关。
为什么 default 方法里不能“写 SQL”?
Default 方法只是普通 Java 代码,它没有被 MyBatis 解析或注册为映射语句。MyBatis 只会扫描:
- Mapper 接口上加了
@Select/@Update等注解的抽象方法; - 与接口同名的 XML 文件中,
<select id="methodName"></select>等定义; - 通过
SqlSession.getMapper()获取代理对象后,调用的是这些被 MyBatis 管理的方法。
default 方法不会生成对应的 MappedStatement,MyBatis 完全感知不到它。
想复用逻辑?推荐这几种安全做法
如果你希望在 Mapper 接口中封装通用查询逻辑(比如分页、动态条件组合),可以这样设计:
- 用 default 方法调用已声明的抽象方法:把 SQL 写在标准的抽象方法上(加注解或配 XML),default 方法只做参数组装、条件判断、多次调用等逻辑。例如:
public interface UserMapper {
@Select("SELECT * FROM user WHERE status = #{status}")
List<user> selectByStatus(@Param("status") int status);
<pre class="brush:php;toolbar:false;">default List<user> selectActiveUsers() {
return selectByStatus(1); // 复用已有 SQL 方法
}</user>
}
- 用 default 方法组合多个已映射操作:比如先查 ID 列表,再批量查详情,只要每个子操作都有对应 SQL 映射即可;
-
配合 BaseMapper 或通用 Mapper(如 tk.mybatis / MyBatis-Plus):它们提供预定义的 default 方法(如
selectByPrimaryKey),背后是通过反射 + 动态代理 + 预置 SQL 模板实现的,不是你在接口里手写 SQL。
绝对不要这样做
以下写法无效且危险:
- 在 default 方法里拼接 SQL 字符串,然后试图用
SqlSession.selectList("xxx")手动执行(因为 "xxx" 不是合法的 statementId,也没有对应映射); - 在 default 方法里 new SqlSessionFactory、手动开 session —— 违反 MyBatis 的使用约定,破坏事务管理、连接复用等核心机制。
真正“写 SQL”的位置只有两个
- 注解方式:写在接口的 抽象方法 上(必须是 public abstract,不能是 default);
-
XML 方式:写在
UserMapper.xml中,<mapper namespace="com.example.UserMapper"></mapper>下的标签内,id 必须与接口方法名一致。
default 方法只能是“胶水”,不是“SQL 容器”。它的价值在于提升接口易用性,而非替代 SQL 声明。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











