Spring源码系列10——Mybatis执行sql流程分析

一、获取sqlsession

Sqlsession中包含了Configuration对象,可以拿到全局配置信息。
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession()

public SqlSession openSession() {
        return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
    }

二、获取执行器

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        executorType = executorType == null ? this.defaultExecutorType : executorType;
        executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
        Object executor;
        if (ExecutorType.BATCH == executorType) {
            executor = new BatchExecutor(this, transaction);
        } else if (ExecutorType.REUSE == executorType) {
            executor = new ReuseExecutor(this, transaction);
        } else {
            executor = new SimpleExecutor(this, transaction);
        }

        if (this.cacheEnabled) {
            executor = new CachingExecutor((Executor)executor);
        }

        Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
        return executor;
    }

执行器分为两大类:一类是CacheExecutor,另一类是普通Executor。
普通Executor又有三种实现:
(1)simpleExecutor:每执行一次update或者select,就开启一个Statement对象,用完就立刻关闭Statement对象。
(2)ReuseExecutor:执行update或者select操作,以sql作为key查找statement对象,存在就重复利用,不存在就存入map中。
(3)BatchExecutor:将所有的sql都添加在批处理对象中,等待统一执行,它缓存了多个Statement对象,等待executeBatch()批处理。

CacheExecutor封装了普通Executor,区别是查询前会先查询缓存中是否有结果,如果缓存中有就从缓存中拿,没有的话,使用普通executor执行,再把结果放入缓存中。

三、获取mapper

org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper

public <T> T getMapper(Class<T> type) {
        return this.configuration.getMapper(type, this);
    }

由于mapper是一个接口所以会生成一个动态代理类。

 public static <T> T newMapperProxy(Class<T> mapperInterface, SqlSession sqlSession) {
        ClassLoader classLoader = mapperInterface.getClassLoader();
        Class<?>[] interfaces = new Class[]{mapperInterface};
        MapperProxy proxy = new MapperProxy(sqlSession);
        return Proxy.newProxyInstance(classLoader, interfaces, proxy);
    }

四、mapper的调用

执行代理后的execute方法,根据mapper.xml中配置的操作标签类型,执行对象的sqlsession的增删改查方法。

public Object execute(Object[] args) {
        Object result = null;
        Object param;
        if (SqlCommandType.INSERT == this.type) {
            param = this.getParam(args);
            result = this.sqlSession.insert(this.commandName, param);
        } else if (SqlCommandType.UPDATE == this.type) {
            param = this.getParam(args);
            result = this.sqlSession.update(this.commandName, param);
        } else if (SqlCommandType.DELETE == this.type) {
            param = this.getParam(args);
            result = this.sqlSession.delete(this.commandName, param);
        } else {
            if (SqlCommandType.SELECT != this.type) {
                throw new BindingException("Unknown execution method for: " + this.commandName);
            }

            if (this.returnsVoid && this.resultHandlerIndex != null) {
                this.executeWithResultHandler(args);
            } else if (this.returnsList) {
                result = this.executeForList(args);
            } else if (this.returnsMap) {
                result = this.executeForMap(args);
            } else {
                param = this.getParam(args);
                result = this.sqlSession.selectOne(this.commandName, param);
            }
        }

        return result;
    }

sqlsession底层会调用executor的增删改查方法,这里以update方法为例。

 public int update(String statement, Object parameter) {
        int var4;
        try {
            this.dirty = true;
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            var4 = this.executor.update(ms, this.wrapCollection(parameter));
        } catch (Exception var9) {
            throw ExceptionFactory.wrapException("Error updating database.  Cause: " + var9, var9);
        } finally {
            ErrorContext.instance().reset();
        }

        return var4;
    }

实际调用的是simpleExecutor的doUpdate方法

public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;

        int var6;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, (ResultHandler)null);
            stmt = this.prepareStatement(handler);
            var6 = handler.update(stmt);
        } finally {
            this.closeStatement(stmt);
        }

        return var6;
    }

然后是调用PreparedStatementHandler类中的方法,有点类似于我们直接jdbc的调用写法了。

 public int update(Statement statement) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.execute();
        int rows = ps.getUpdateCount();
        Object parameterObject = this.boundSql.getParameterObject();
        KeyGenerator keyGenerator = this.mappedStatement.getKeyGenerator();
        keyGenerator.processAfter(this.executor, this.mappedStatement, ps, parameterObject);
        return rows;
    }

query的调用更能说明问题:

public List query(Statement statement, ResultHandler resultHandler) throws SQLException {
        PreparedStatement ps = (PreparedStatement)statement;
        ps.execute();
        return this.resultSetHandler.handleResultSets(ps);
    }

总结:其实就是对jdbc的层层封装和功能完善。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值