出于好奇,然后就有了这篇文章啦。 源码给我的感觉,是一座大山的感觉。曲曲折折的路很多,点进去就有可能出不来。 不过慢慢看下来,收货是有的,对一些理解更为深刻了,而且越来越觉得数据结构是真的真的重要,底层的类,就没有不用到数据结构的。
传进来的参数text
是 select t_user.id,t_user.username,t_user.password from t_user where t_user.id=#{id}
这里需要做的就是讲#{id} 替换成 ?。
package org.apache.ibatis.parsing;
/**
* @author Clinton Begin
*/
public class GenericTokenParser {
private final String openToken; // openToken: "#{"
private final String closeToken; // closeToken: "}"
// 这里实际调用的是TokenHandler的实现类 SqlSourceBuilder类中的ParameterMappingTokenHandler
private final TokenHandler handler;
public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
this.openToken = openToken;
this.closeToken = closeToken;
this.handler = handler;
}
public String parse(String text) {
if (text == null || text.isEmpty()) {
return "";
}
// search open token
// 这里就是找到 "#{" 的起始位置
int start = text.indexOf(openToken);
if (start == -1) {
return text;
}
// 将text划分为 字符数组
char[] src = text.toCharArray();
int offset = 0;
//StringBuilder 文末有讲 可理解为 StringBuffer
final StringBuilder builder = new StringBuilder();
StringBuilder expression = null;
do {
if (start > 0 && src[start - 1] == '\\') {
// this open token is escaped. remove the backslash and continue.
builder.append(src, offset, start - offset - 1).append(openToken);
offset = start + openToken.length();
} else {
// found open token. let's search close token.
if (expression == null) {
expression = new StringBuilder();
} else {
expression.setLength(0);
}
builder.append(src, offset, start - offset);
//"select t_user.id,t_user.username,t_user.password from t_user where t_user.id="
// 可以理解为 将去除了#{} 的sql 语句 重新赋值给 builder啦
offset = start + openToken.length();// 定位到参数的开始位置
// 从 offset 索引开始搜索 "}" 出现的位置 赋给end
int end = text.indexOf(closeToken, offset);
while (end > -1) {
if (end > offset && src[end - 1] == '\\') {
// this close token is escaped. remove the backslash and continue.
expression.append(src, offset, end - offset - 1).append(closeToken);
offset = end + closeToken.length();
end = text.indexOf(closeToken, offset);
} else {
// 取到"id" 然后添加进 expression
expression.append(src, offset, end - offset);
break;
}
}
if (end == -1) {
// close token was not found.
builder.append(src, start, src.length - start);
offset = src.length;
} else {
// 此时 handler.handleToken(expression.toString()) 返回值 实际就是 "? "
// 但之中还做了其他操作,我们暂不分析。
builder.append(handler.handleToken(expression.toString()));
offset = end + closeToken.length();
}
}
start = text.indexOf(openToken, offset);
} while (start > -1);
if (offset < src.length) {
builder.append(src, offset, src.length - offset);
}
//此时 返回的已是: select t_user.id,t_user.username,t_user.password from t_user where t_user.id=?
return builder.toString();
}
}
@Override
public String handleToken(String content) {
parameterMappings.add(buildParameterMapping(content));
return "?";
}
在这个方法中,其返回值就是返回一个“?” 。buildParameterMapping(content)
做了一些操作,看起来像检验类型,我没有完全看懂,不乱说。 parameterMappings.add();
这个 parameterMappings 实际上是一个 private List parameterMappings = new ArrayList<>(); List的数据结构 存储。这步操作肯定是有用的,但是我目前还没有明白哈。
虽然对于mybatis 仍然感觉什么都没有懂,都只是出于好奇,去探究一下。 但是在这个过程中,我深刻的感受到了数据结构的重要性,底层的存储不是Map 就是List 等等。 就像Mybatis 的一级缓存,二级缓存等等,他们的底层存储就是依赖于不同的数据结构的。