注:
大家好我是妈妈的好大儿,
笔者联系方式
QQ:3302254385
微信:yxc3302254385
交个朋友!
创作不易,三连十分感谢!!!,
由于近期有一个重推物流信息的刷数据需求,在实际生产过程中发生多次oom导致服务down机,最后通过skyWalKing排查原因发现是因为全表扫描导致的问题!
最终定位到具体的代码 见下
LopWrapDistribution distribution = new LopWrapDistribution();
distribution.setWrapNo(wrapNo);
List distributionList = distributionMapper.select(distribution);
由于wrapNo为空导致wrap_no条件不生效,导致最后的查询语句变成,见下,导致全表扫描
SELECT * FROM lop_wrap_distribution
本应该是
SELECt * FROM lop_wrap_distribution where wrap_no = #{?}
对于数据量特别大的表,这是一个特别特别严重切无法容忍的问题,不单单会导致服务oom,也会导致占用mysql的性能
问题原因解析先看一下tk.mybatis所使用的版本
tk.mybatis mapper 3.3.6
然后我们去看一下tkmapper在底层是怎么构建你的查询语句
首先是第一层,我们的抽象接口
public interface SelectMapper{ @SelectProvider(type = BaseSelectProvider.class, method = "dynamicSQL") List select(T record); }
第二层,我们的基础查询具体实现类,看到select方法
public class BaseSelectProvider extends MapperTemplate {
public String select(MappedStatement ms) {
Class> entityClass = getEntityClass(ms);
//修改返回值类型为实体类型
setResultType(ms, entityClass);
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.selectAllColumns(entityClass));
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty()));
sql.append(SqlHelper.orderByDefault(entityClass));
return sql.toString();
}
}
第三层SqlHelper.whereAllIfColumns
这里可以很明显的看到,现在构建XXmapper.xml中执行的SQL语句,来拼接我们where条件部分
public static String whereAllIfColumns(Class> entityClass, boolean empty) {
StringBuilder sql = new StringBuilder();
sql.append("");
//获取全部列
Set columnList = EntityHelper.getColumns(entityClass);
//当某个列有主键策略时,不需要考虑他的属性是否为空,因为如果为空,一定会根据主键策略给他生成一个值
for (EntityColumn column : columnList) {
sql.append(getIfNotNull(column, " AND " + column.getColumnEqualsHolder(), empty));
}
sql.append(" ");
return sql.toString();
}
第四层 拼接SQL的具体实现
我们首先关注
sql.append(getIfNotNull(column, " AND " +column.getColumnEqualsHolder(), empty));
此行代码,然后再一路点下去,见到下面代码为止
public static String getIfNotNull(String entityName, EntityColumn column, String contents, boolean empty) {
StringBuilder sql = new StringBuilder();
sql.append("
sql.append(entityName).append(".");
}
sql.append(column.getProperty()).append(" != null");
if (empty && column.getJavaType().equals(String.class)) {
sql.append(" and ");
if (StringUtil.isNotEmpty(entityName)) {
sql.append(entityName).append(".");
}
sql.append(column.getProperty()).append(" != '' ");
}
sql.append("">");
sql.append(contents);
sql.append(" ");
return sql.toString();
}
很轻易的就能看明白,这里在写
结论
当我们的对象属性为空时,或者为空字符时,会把此字段忽略掉,从而有可能导致全表扫描



