前言
博主最近在基于 [smpe](www.baidu.com) 开源框架去写一个项目,但是因为数据库的表需要修改,一些mapper的sql也需要做修改。为了保证原有项目的可运行,就直接在mapper.class下进行了重载,但是结果却不对。一、情景再现
提示:为了详细说明,本篇博客就快速创建简单的mapper和数据库表进行演示。
1. sql
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
INSERT INTO `role` VALUES (1, '测试角色1');
INSERT INTO `role` VALUES (2, '角色2');
INSERT INTO `role` VALUES (3, '青山');
2. Mapper
public interface RoleMapper extends BaseMapper<Role> {
@Select("SELECT r.* FROM role r where r.id = #{id} and r.name = #{name}")
public List<Role> getRole(Long id, String name);
@Select("SELECT r.* FROM role r where r.id = #{id}")
public List<Role> getRole(Long id);
}
3. 测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MapperTest {
@Autowired
private RoleMapper roleMapper;
@Test
public void TestMapper() {
List<Role> list= roleMapper.getRole(3l);
List<Role> list2 = roleMapper.getRole(3l, "青山");
System.out.println(list);
System.out.println(list2);
}
}
4.结果
从结果上看我们发现,只有传入两个参数的方法才是执行成功的。
二、问题分析
1.通过查看执行sql
- 单个参数的sql执行情况
- 多参数的sql执行情况
从结果上看,虽然mapper接口确实对sql进行重载,编译也顺利通过,但是最终执行的还是Mapper中第一个被写入的方法
。之后经过将mapper的两个方法顺序调换,都是调用的单参数sql的方法
。
2. 查看源码
在通过debug断点执行的时候,在MapperMethod类
中发现了executeForMany
方法(这个方法是mapper代理查询集合的最终执行目标),
executeForMany代码如下(示例):
private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
List<E> result;
Object param = method.convertArgsToSqlCommandParam(args);
if (method.hasRowBounds()) {
RowBounds rowBounds = method.extractRowBounds(args);
result = sqlSession.selectList(command.getName(), param, rowBounds);
} else {
// 重点行 command ,command.getName()的值为全称方法名:com.mapper.RolerMapper.getRole,不包含参数列表
result = sqlSession.selectList(command.getName(), param);
}
if (!method.getReturnType().isAssignableFrom(result.getClass())) {
if (method.getReturnType().isArray()) {
return convertToArray(result);
} else {
return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
}
}
return result;
}
结果从mapper的代理对象选择sql的方式就可以看出来,mapper在执行接口方法的时候是不管重载方法的参数列表
以及返回列表
,因此对于mybatis来说也就不存在重载了。
总结
Mybatis不支持方法重载
,但是java本身是一定支持重载的。- Mybatis获取执行方法是同一个key从内存在获取的,key的结构为
包名.方法名
,不包括方法参数列表
和方法返回值
。 - Mybatis的这种方式应该和mapper的扫描和生成mapper代理的方式有关,
需要研究
。