• 记一次解决问题过程


    缘起

    由于公司多数中间件基于ibatis2,并且在sql方面基本全部动态化,在开发阶段基本不可能知道sql最终的形态,这对测试的准确性带来了一定的困难,所以就有了这么一个Action, 对ibatis2测试环境进行扩展,在重要的测试场景能够等到最终运行的sql,用来与预期的sql进行比较。

    思路

    拿到问题大致看了一下ibatis2源码发现sql语句在MappedStatement可以透出,这里具体怎么通过MappedStatement得到就不深究了,这里主要记录一下解决问题的思路。那么有了这个结论问题就很明确了,我们主要拿到MappedStatement就可以了!带着这个问题我们继续从ibatis2入口深入,发现基本调用流程如下:

    SqlMapClientFactoryBean->SqlMapClient->SqlMapSession->SqlMapExecutorDelegate ;所有的类似insert、update、delete...执行最终都会落到SqlMapExecutorDelegate

    然而在 SqlMapExecutorDelegate提供了 getMappedStatement(String id)方法可以拿到我们需要的MappedStatement。接着我对SqlMapClientFactoryBean(一个Spring bean工厂)进行分析,发现下面这段代码:

    
        //spring InitializingBean 在bean创建后的处理
        public void afterPropertiesSet() throws Exception {
            if (this.lobHandler != null) {
                configTimeLobHandlerHolder.set(this.lobHandler);
            }
    
            try {
                // 非常关键的方法, 这里创建了 sqlMapClient,方法内容看下面。
                this.sqlMapClient = this.buildSqlMapClient(this.configLocations, this.mappingLocations, this.sqlMapClientProperties);
                if (this.dataSource != null) {
                    TransactionConfig transactionConfig = (TransactionConfig)this.transactionConfigClass.newInstance();
                    DataSource dataSourceToUse = this.dataSource;
                    if (this.useTransactionAwareDataSource && !(this.dataSource instanceof TransactionAwareDataSourceProxy)) {
                        dataSourceToUse = new TransactionAwareDataSourceProxy(this.dataSource);
                    }
    
                    transactionConfig.setDataSource((DataSource)dataSourceToUse);
                    transactionConfig.initialize(this.transactionConfigProperties);
                    this.applyTransactionConfig(this.sqlMapClient, transactionConfig);
                }
            } finally {
                if (this.lobHandler != null) {
                    configTimeLobHandlerHolder.remove();
                }
    
            }
    
        }
    
        protected SqlMapClient buildSqlMapClient(Resource[] configLocations, Resource[] mappingLocations, Properties properties) throws IOException {
            if (ObjectUtils.isEmpty(configLocations)) {
                throw new IllegalArgumentException("At least 1 'configLocation' entry is required");
            } else {
                SqlMapClient client = null;
                SqlMapConfigParser configParser = new SqlMapConfigParser();
                Resource[] var9 = configLocations;
                int var8 = configLocations.length;
    
                for(int var7 = 0; var7 < var8; ++var7) {
                    Resource configLocation = var9[var7];
                    InputStream is = configLocation.getInputStream();
    
                    try {
                        client = configParser.parse(is, properties);
                    } catch (RuntimeException var13) {
                        throw new NestedIOException("Failed to parse config resource: " + configLocation, var13.getCause());
                    }
                }
    
                if (mappingLocations != null) {
                    SqlMapParser mapParser = SqlMapClientFactoryBean.SqlMapParserFactory.createSqlMapParser(configParser);
                    Resource[] var14 = mappingLocations;
                    int var17 = mappingLocations.length;
    
                    for(var8 = 0; var8 < var17; ++var8) {
                        Resource mappingLocation = var14[var8];
    
                        try {
                            mapParser.parse(mappingLocation.getInputStream());
                        } catch (NodeletException var12) {
                            throw new NestedIOException("Failed to parse mapping resource: " + mappingLocation, var12);
                        }
                    }
                }
    
                return client;
            }
        }
    

    从这段代码我们明确了SqlMapClient的产出,而SqlMapClient持有SqlMapExecutorDelegateSqlMapSession,下面我们就看看这些个对象的关系:

    public class SqlMapClientImpl implements SqlMapClient, ExtendedSqlMapClient {
        private static final Log log = LogFactory.getLog(SqlMapClientImpl.class);
        public SqlMapExecutorDelegate delegate;
        protected ThreadLocal localSqlMapSession = new ThreadLocal();
    
        public SqlMapClientImpl(SqlMapExecutorDelegate delegate) {
            this.delegate = delegate;
        }
    }
    

    看到这里估计大家思路应该就清楚了吧,我如果让SqlMapClientFactoryBean返回我自定义的SqlMapClient,我自定义的SqlMapClient使用我自定义的SqlMapExecutorDelegate,这样我就可以对SqlMapExecutorDelegate进行包装了,比如给insert、update、query这一类方法添加前置、后置处理,进而达到我们的目的了。

    最后

    最后呢,在这里贴一下源码,有兴趣可以看看,不过这种老版本的ibatis感觉用的人也比较少了。

  • 相关阅读:
    【Linux】Linux服务器(centos7)安装配置 redis
    【java】使用 starter 的方式在 SpringBoot 中整合 Shiro
    【Docker】使用 Docker 基于centos7 构建 java 环境容器
    c#经典三层框架中的SqlHelper帮助类
    SOD框架的Model、连接数据库及增删改查
    用bat文件更改ip地址
    postgresql 创建并使用uuid作为唯一主键
    postgresql 查询字符串中是否包含某字符的几种写法
    pycharm激活码
    c# DataTable第二行改为各列标题字段
  • 原文地址:https://www.cnblogs.com/learningchencheng/p/10511465.html
Copyright © 2020-2023  润新知