您的位置:首页 > 数据库

Mybatis 动态SQL之<trim>,<where>,<set>源码解析

2017-12-06 21:37 453 查看
Mybatis的trim,where,set这几个sql节点能动态的去除sql片段的前缀或后缀,我们先来看解析trim节点的代码:

public class TrimSqlNode implements SqlNode {

private SqlNode contents;
private String prefix;
private String suffix;
private List<String> prefixesToOverride;  //可被覆盖的前缀集合,可以在trim节点内指定多个
private List<String> suffixesToOverride;  //可被覆盖的后缀集合,可以在trim节点内指定多个
private Configuration configuration;

public TrimSqlNode(Configuration configuration, SqlNode contents, String prefix, String prefixesToOverride, String suffix, String suffixesToOverride) {
this(configuration, contents, prefix, parseOverrides(prefixesToOverride), suffix, parseOverrides(suffixesToOverride));
}

protected TrimSqlNode(Configuration configuration, SqlNode contents, String prefix, List<String> prefixesToOverride, String suffix, List<String> suffixesToOverride) {
this.contents = contents;
this.prefix = prefix;
this.prefixesToOverride = prefixesToOverride;
this.suffix = suffix;
this.suffixesToOverride = suffixesToOverride;
this.configuration = configuration;
}

@Override
public boolean apply(DynamicContext context) {
FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context);
boolean result = contents.apply(filteredDynamicContext); //这个方法是主要方法,执行此方法,根据给的参数解析内部的if节点,生成sql字符串
filteredDynamicContext.applyAll(); //当内部的if或者其他节点解析完毕后,解析自身trim节点
return result;
}

private static List<String> parseOverrides(String overrides) {
if (overrides != null) {
final StringTokenizer parser = new StringTokenizer(overrides, "|", false);
final List<String> list = new ArrayList<String>(parser.countTokens());
while (parser.hasMoreTokens()) {
list.add(parser.nextToken().toUpperCase(Locale.ENGLISH));
}
return list;
}
return Collections.emptyList();
}

private class FilteredDynamicContext extends DynamicContext {
private DynamicContext delegate;
private boolean prefixApplied;
private boolean suffixApplied;
private StringBuilder sqlBuffer;

public FilteredDynamicContext(DynamicContext delegate) {
super(configuration, null);
this.delegate = delegate;
this.prefixApplied = false;
this.suffixApplied = false;
this.sqlBuffer = new StringBuilder();
}

public void applyAll() {
sqlBuffer = new StringBuilder(sqlBuffer.toString().trim());
String trimmedUppercaseSql = sqlBuffer.toString().toUpperCase(Locale.ENGLISH);
if (trimmedUppercaseSql.length() > 0) {
applyPrefix(sqlBuffer, trimmedUppercaseSql);  //解析前缀
applySuffix(sqlBuffer, trimmedUppercaseSql);  //解析后缀
}
delegate.appendSql(sqlBuffer.toString());
}

@Override
public Map<String, Object> getBindings() {
return delegate.getBindings();
}

@Override
public void bind(String name, Object value) {
delegate.bind(name, value);
}

@Override
public int getUniqueNumber() {
return delegate.getUniqueNumber();
}

@Override
public void appendSql(String sql) {
sqlBuffer.append(sql);
}

@Override
public String getSql() {
return delegate.getSql();
}

private void applyPrefix(StringBuilder sql, String trimmedUppercaseSql) {
if (!prefixApplied) {
prefixApplied = true;
if (prefixesToOverride != null) {
for (String toRemove : prefixesToOverride) {
if (trimmedUppercaseSql.startsWith(toRemove)) {
sql.delete(0, toRemove.trim().length());  //如果内部节点解析后生成的sql存在prefixOverrides,删除prefixOverrides
break;
}
}
}
if (prefix != null) {  //当指定了prefix时,在sql的最开始处加上prefix
sql.insert(0, " ");
sql.insert(0, prefix);
}
}
}

private void applySuffix(StringBuilder sql, String trimmedUppercaseSql) {
if (!suffixApplied) {
suffixApplied = true;
if (suffixesToOverride != null) {
for (String toRemove : suffixesToOverride) {
if (trimmedUppercaseSql.endsWith(toRemove) || trimmedUppercaseSql.endsWith(toRemove.trim())) {
int start = sql.length() - toRemove.trim().length();
int end = sql.length();
sql.delete(start, end);  //sql以suffixOverrides结尾时,删除suffixOverrides
break;
}
}
}
if (suffix != null) { //当指定了suffix ,在sql结尾加上suffix
sql.append(" ");
sql.append(suffix);
}
}
}

}

}


以上就是trm的解析逻辑,看代码容易明白。

set和where节点解析类继承TrimSqlNode 。

set的解析逻辑相对trim来说,仅仅只是指定了prefix = SET,suffixesToOverride = “,”,也就是说sql加个前缀SET,如果sql以”,”结尾删除最后一个”,”;

where的解析逻辑相对trim来说,仅仅只是指定了prefi = WHERE,prefixesToOverride= AND | OR,也就是说sql加个前缀WHERE,如果sql以”AND”或者”OR”开始删除开始的”AND”或者”OR”;

public class SetSqlNode extends TrimSqlNode {

private static List<String> suffixList = Arrays.asList(",");

public SetSqlNode(Configuration configuration,SqlNode contents) {
super(configuration, contents, "SET", null, null, suffixList);
}

}

public class WhereSqlNode extends TrimSqlNode {

private static List<String> prefixList = Arrays.asList("AND ","OR ","AND\n", "OR\n", "AND\r", "OR\r", "AND\t", "OR\t");

public WhereSqlNode(Configuration configuration, SqlNode contents) {
super(configuration, contents, "WHERE", prefixList, null, null);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mybatis