zoukankan      html  css  js  c++  java
  • 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:

  • 相关阅读:
    图像检索(image retrieval)- 11
    图像检索(image retrieval)- 10相关
    Mock.js简易教程,脱离后端独立开发,实现增删改查功能
    Azure Monitor (3) 对虚拟机磁盘设置自定义监控
    Azure Monitor (1) 概述
    Azure SQL Managed Instance (2) 备份SQL MI
    Azure Virtual Network (17) Private Link演示
    Azure Virtual Network (16) Private Link
    Azure Virtual Network (15) Service Endpoint演示
    Azure Virtual Network (14) Service Endpoint服务终结点
  • 原文地址:https://www.cnblogs.com/lanqie/p/8483438.html
Copyright © 2011-2022 走看看