mybatis加载xml文件错误及其影响

来源:互联网 发布:淘宝hd老版本 编辑:程序博客网 时间:2024/05/22 00:24

一次在做一个项目的过程中,发现mybatis加载xml文件错误,导致了后面所有的sql都报了这个sql语句的错误,一时没有摸到头脑,在此分析下。

在mybatis加载xml文件的时候,会解析所有的文件,同时把statement错误的文件放到一个集合中去,代码如下:

  private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {    for (XNode context : list) {      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);      try {        statementParser.parseStatementNode();      } catch (IncompleteElementException e) {        configuration.addIncompleteStatement(statementParser);      }    }  }

重点看catch中的语句:

  public void addIncompleteStatement(XMLStatementBuilder incompleteStatement) {    incompleteStatements.add(incompleteStatement);  }

incompleteStatements是加载错误的Statements集合。而当每次执行任何sql语句的时候,都会检查incompleteStatements是否为空,如果为空的话,就一直报那个加载错误的xml文件。代码如下:

我们从MapperProxy类的invoke方法一直往下走:

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    if (method.getDeclaringClass() == Object.class) {      return method.invoke(this, args);    }    final Class<?> declaringInterface = findDeclaringInterface(proxy, method);    final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession);    final Object result = mapperMethod.execute(args);    if (result == null && method.getReturnType().isPrimitive() && !method.getReturnType().equals(Void.TYPE)) {      throw new BindingException("Mapper method '" + method.getName() + "' (" + method.getDeclaringClass() + ") attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");    }    return result;  }

  public MapperMethod(Class<?> declaringInterface, Method method, SqlSession sqlSession) {    paramNames = new ArrayList<String>();    paramPositions = new ArrayList<Integer>();    this.sqlSession = sqlSession;    this.method = method;    this.config = sqlSession.getConfiguration();    this.hasNamedParameters = false;    this.declaringInterface = declaringInterface;    this.objectFactory = config.getObjectFactory();    setupFields();//设置字段    setupMethodSignature();//设置方法验证    setupCommandType();//命令类型:select,update,delete,insert    validateStatement();//验证statement  }

  private void setupCommandType() {    MappedStatement ms = config.getMappedStatement(commandName);    type = ms.getSqlCommandType();    if (type == SqlCommandType.UNKNOWN) {      throw new BindingException("Unknown execution method for: " + commandName);    }  }
在获取命令类型前,先获取到MappedStatement,同时在获取MappedStatement前会有一个验证,是否有未完成的Statement:

  public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {    if (validateIncompleteStatements) {      buildAllStatements();    }    return mappedStatements.get(id);  }

  protected void buildAllStatements() {    if (!incompleteResultMaps.isEmpty()) {      synchronized (incompleteResultMaps) {        // This always throws a BuilderException.        incompleteResultMaps.iterator().next().resolve();      }    }    if (!incompleteCacheRefs.isEmpty()) {      synchronized (incompleteCacheRefs) {        // This always throws a BuilderException.        incompleteCacheRefs.iterator().next().resolveCacheRef();      }    }    if (!incompleteStatements.isEmpty()) {      synchronized (incompleteStatements) {        // This always throws a BuilderException.        incompleteStatements.iterator().next().parseStatementNode();      }    }  }

如果有未完成是MappedStatement的话就会,继续完成转化MappedStatement,如果转化出错,则会直接抛出异常。

阅读全文
0 0