问题重现
需要将以下map的value插入到sql的占位符当中:
map = {
"Product2.Product2" : "Garden Li"
}
数据:
id | name |
---|---|
26 | Garden Li |
mapper interface 如下:
Student selectByMap(@Param("paramsMap") Map<String, Object> map);
mapper.xml如下:
<select id="selectByMap" parameterType="java.util.Map" resultMap="BaseResultMap">
select
*
from student
where name = #{paramsMap.Product2.Product2}
</select>
入参情形
Map<String, Object> map = new HashMap<>();
map.put("Product2.Product2", "Garden Li");
Student student = studentMapper.selectByMap(map);
System.out.println(student);
日志结果
==> Preparing: select * from student where name = ?
==> Parameters: null
<== Total: 0
结论:异常,并未达到预期结果。
排查过程
根据Mybatis底层实现,优先找到参数处理的类,即ParameterHandler接口的默认实现DefaultParameterHandler:
/**
* @author Clinton Begin
* @author Eduardo Macarron
*/
public class DefaultParameterHandler implements ParameterHandler
debug到参数解析类PropertyTokenizer的解析方法:
public PropertyTokenizer(String fullname) {
int delim = fullname.indexOf('.');
if (delim > -1) {
name = fullname.substring(0, delim);
children = fullname.substring(delim + 1);
} else {
name = fullname;
children = null;
}
indexedName = name;
delim = name.indexOf('[');
if (delim > -1) {
index = name.substring(delim + 1, name.length() - 1);
name = name.substring(0, delim);
}
}
判断出Mybatis不能处理带多个【.】的占位符入参
解决方案
配合Mybatis的原理实现,构造嵌套的map进行正常处理:
Map<String, Object> innerMap = new HashMap<>();
innerMap.put("Product2", "Garden Li");
Map<String, Object> map = new HashMap<>();
map.put("Product2", innerMap);
Student student = studentMapper.selectByMap(map);
System.out.println(student);
日志结果:
==> Preparing: select * from student where name = ?
==> Parameters: Garden Li(String)
<== Columns: id, name
<== Row: 26, Garden Li
<== Total: 1