Mybatis 接口 Mapper 内的方法为什么不能重载?

Mybatis中Mapper接口的工作原理

对应的关系如下:

  • 接口的全限名,就是xml映射文件中的 "namespace" 的值。
  • 接口的方法名,就是xml映射文件中 MappedStatement 的 "id" 值。
  • 接口方法内的参数,就是传递给 SQL 的参数。

Mapper 接口是没有实现类的,当调用接口方法时,接口全限名 + 方法名拼接字符串作为 key 值,可唯一定位一个对应的 MappedStatement

例如,如下接口全限名 + 方法名拼接字符串作为key

com.coderjia.content.app.dao.IActivityDao#addSignInLog

可以定位到namespace

com.coderjia.content.app.dao.IActivityDao

中id为"addSignInLog"MappedStatement

Mybatis 中,每一个 <insert/><delete/><update/><select/>标签,都会被解析为一个 MappedStatement 对象,和Mapper里的接口一一对应。


再看看重载

重载(Overload)是一个类中多态性的一种表现。如果在一个类中定义了多个同名的方法,它们参数列表不同,则称为方法的重载(Overload)。

Mapper接口在定位MappedStatement时是不使用参数来定位的,所以重载的接口方法是无法唯一定位到其匹配的MappedStatement的。


在 MyBatis 中,Mapper 接口的方法不能重载的原因主要是因为 MyBatis 是通过 Mapper 接口方法名来映射 SQL 语句的。如果允许方法重载,会导致方法名相同但参数不同的情况,这样 MyBati就无法准确地根据方法名来映射正确的 SQL 语句。

public interface UserMapper {
    User getUserById(int id);
    User getUserByName(String name);
}

假设允许方法重载,那么在调用 getUser 方法时,无法确定是要执行哪个 SQL 语句,因为方法名相同,参数不同。为了避免这种混淆,MyBatis 不支持在 Mapper 接口中定义方法重载。

解决这个问题的一种方法是使用不同的方法名来表示不同的查询,如:

public interface UserMapper {
    User getUserById(int id);
    User getUserByName(String name);
}

需要注意的是,虽然在 Mapper 接口中不能直接定义方法重载,但在 XML 映射文件中是可以定义多个不同参数的 SQL 语句并通过不同的 id 进行区分的。这样就能够实现不同参数的查询操作。


从底层简单说一下:

MyBatis的底层工作原理涉及到了Java的反射机制和动态代理技术,而方法重载涉及到方法的参数列表,这会导致在底层实现时产生歧义,因此MyBatis禁止了Mapper接口方法的重载。

展开阅读全文

本文系作者在时代Java发表,未经许可,不得转载。

如有侵权,请联系nowjava@qq.com删除。

编辑于

关注时代Java

关注时代Java