• MyBatis-进阶1


    接入门的实例,我们知道MyBatis可以使用注解和配置文件实现接口和sql语句的绑定。

    那么一个接口方法同时使用注解和xml配置会怎么样。

        @Select("select * from user_tb where id=#{id}")
        User getOneUser(int id);
    
        <select id="getOneUser" resultType="User">
            select * from user_tb where id+1=#{id}
        </select>
    

    如果传入id=12,查出来的User.id=12,说明注解覆盖xml配置,查出来的User.id=11,说明xml配置覆盖注解

    结果是:

    Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: 
    ### Error building SqlSession.
    ### The error may exist in com/xh/mybatisLearn/dao/UserMapper.java (best guess)
    ### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.xh.mybatisLearn.dao.UserMapper.getOneUser
    	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
    	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:80)
    	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:64)
    	at com.xh.mybatisLearn.Test.getSqlSessionFactory(Test.java:29)
    	at com.xh.mybatisLearn.Test.main(Test.java:34)
    

    竟然抛异常啦,去掉任何一个都是可以的。其实这个可以理解,因为实在没有理由这么干。

    我现在想看看到时是哪个方法抛出异常的怎么办?

    我的办法是边debug边下断点:

    比如第一次在执行A()抛异常,那么就在A处下断点,下次运行到A的时候进入,然后B()抛异常,在B()下断点。。。。

    如果经过的方法很多可以去掉之前的一些断点,只保留关键的方法(后期需要分析)

    可能有人喜欢边debug边读源码,但我偏好先不读代码,找到抛出异常的源头,回头在根据断点一步步看源码,这样脉络更清晰。

    异常是由:Configuration.class抛出

            public V put(String key, V value) {
                if(this.containsKey(key)) {
                    throw new IllegalArgumentException(this.name + " already contains value for " + key);
                } else {
    

    key:com.xh.mybatisLearn.dao.UserMapper.getOneUser

    value:MappedStatement对象

     原来是这里保证了每个接口方法只有一个MappedStatement对象。

        public void addMappedStatement(MappedStatement ms) {
            this.mappedStatements.put(ms.getId(), ms);
        }
    

     Configuration有这个属性:

    protected final Map<String, MappedStatement> mappedStatements;
    

    ++++++++++++++++++++++++++

    debug关键步骤:

    XMLConfigBuilder.class解析节点

        private void mapperElement(XNode parent) throws Exception {
            if(parent != null) {
                Iterator i$ = parent.getChildren().iterator();
    
                while(true) {
                    while(i$.hasNext()) {
                        XNode child = (XNode)i$.next();
                        String resource;
                        if("package".equals(child.getName())) {
                            resource = child.getStringAttribute("name");
                            this.configuration.addMappers(resource);
                        } else {
                            resource = child.getStringAttribute("resource");
                            String url = child.getStringAttribute("url");
                            String mapperClass = child.getStringAttribute("class");
                            XMLMapperBuilder mapperParser;
                            InputStream mapperInterface1;
                            if(resource != null && url == null && mapperClass == null) {
                                ErrorContext.instance().resource(resource);
                                mapperInterface1 = Resources.getResourceAsStream(resource);
                                mapperParser = new XMLMapperBuilder(mapperInterface1, this.configuration, resource, this.configuration.getSqlFragments());
                                mapperParser.parse();<---------------------
                            } else if(resource == null && url != null && mapperClass == null) {
    

    MapperBuilderAssistant.class:

        public MappedStatement addMappedStatement(String id, SqlSource sqlSource, StatementType statementType, SqlCommandType sqlCommandType, Integer fetchSize, Integer timeout, String parameterMap, Class<?> parameterType, String resultMap, Class<?> resultType, ResultSetType resultSetType, boolean flushCache, boolean useCache, boolean resultOrdered, KeyGenerator keyGenerator, String keyProperty, String keyColumn, String databaseId, LanguageDriver lang, String resultSets) {
            if(this.unresolvedCacheRef) {
                throw new IncompleteElementException("Cache-ref not yet resolved");
            } else {
                id = this.applyCurrentNamespace(id, false);
                boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
                org.apache.ibatis.mapping.MappedStatement.Builder statementBuilder = (new org.apache.ibatis.mapping.MappedStatement.Builder(this.configuration, id, sqlSource, sqlCommandType)).resource(this.resource).fetchSize(fetchSize).timeout(timeout).statementType(statementType).keyGenerator(keyGenerator).keyProperty(keyProperty).keyColumn(keyColumn).databaseId(databaseId).lang(lang).resultOrdered(resultOrdered).resultSets(resultSets).resultMaps(this.getStatementResultMaps(resultMap, resultType, id)).resultSetType(resultSetType).flushCacheRequired(((Boolean)this.valueOrDefault(Boolean.valueOf(flushCache), Boolean.valueOf(!isSelect))).booleanValue()).useCache(((Boolean)this.valueOrDefault(Boolean.valueOf(useCache), Boolean.valueOf(isSelect))).booleanValue()).cache(this.currentCache);
                ParameterMap statementParameterMap = this.getStatementParameterMap(parameterMap, parameterType, id);
                if(statementParameterMap != null) {
                    statementBuilder.parameterMap(statementParameterMap);
                }
    
                MappedStatement statement = statementBuilder.build();
                this.configuration.addMappedStatement(statement);<---------------------
                return statement;
            }
        }
    

    MapperRegistry.class:

        public <T> void addMapper(Class<T> type) {
            if(type.isInterface()) {
                if(this.hasMapper(type)) {
                    throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
                }
    
                boolean loadCompleted = false;
    
                try {
                    this.knownMappers.put(type, new MapperProxyFactory(type));
                    MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
                    parser.parse();<---------------------
                    loadCompleted = true;
    

    MapperAnnotationBuilder.class:

    this.assistant.addMappedStatement(mappedStatementId, sqlSource, statementType, sqlCommandType, fetchSize, timeout, (String)null, parameterTypeClass, var26, this.getReturnType(method), resultSetType, flushCache, useCache, false, (KeyGenerator)keyGenerator, keyProperty, keyColumn, (String)null, languageDriver, options != null?this.nullOrEmpty(options.resultSets()):null);
     this.configuration.addMappedStatement(statement);
    

     最后回到:Configuration.class:

  • 相关阅读:
    iOS开发 如何检查内存泄漏
    iOS开发工具篇-AppStore统计工具
    10个必需的iOS开发工具和资源
    Eclipse的调试功能的10个小窍门[转]
    Eclipse远程调试应用程序
    MySQL学习笔记(二)
    Java内存回收机制基础[转]
    MySQL学习笔记(一)
    MySQL死锁[转]
    java编码规范
  • 原文地址:https://www.cnblogs.com/lanqie/p/8483438.html
Copyright © 2020-2023  润新知