MyBatis(3)-执行流程

SQL执行流程

MyBatis总是通过SqlSessionFactoryBuilder创建SqlSessionFactory,然后用SqlSessionFactory创建SqlSession,再用SqlSession获取Mapper接口来进行SQL操作。
通过SqlSession.getMapper -> this.configuration.getMapper(type, this) -> this.mapperRegistry.getMapper(type, sqlSession) -> mapperProxyFactory.newInstance(sqlSession) -> Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{ this.mapperInterface}, mapperProxy)获得了一个Mapper接口类型的反射代理类。其中MapperProxy类用来处理Mapper接口函数的请求:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, args);
        }

        if (this.isDefaultMethod(method)) {
            return this.invokeDefaultMethod(proxy, method, args);
        }
    } catch (Throwable var5) {
        throw ExceptionUtil.unwrapThrowable(var5);
    }

    MapperMethod mapperMethod = this.cachedMapperMethod(method);
    return mapperMethod.execute(this.sqlSession, args);
}
public Object execute(SqlSession sqlSession, Object[] args) {
    Object param;
    Object result;
    switch(this.command.getType()) {
    case INSERT:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
        break;
    case UPDATE:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
        break;
    case DELETE:
        param = this.method.convertArgsToSqlCommandParam(args);
        result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
        break;
    case SELECT:
        if (this.method.returnsVoid() && this.method.hasResultHandler()) {
            this.executeWithResultHandler(sqlSession, args);
            result = null;
        } else if (this.method.returnsMany()) {
            result = this.executeForMany(sqlSession, args);
        } else if (this.method.returnsMap()) {
            result = this.executeForMap(sqlSession, args);
        } else if (this.method.returnsCursor()) {
            result = this.executeForCursor(sqlSession, args);
        } else {
            param = this.method.convertArgsToSqlCommandParam(args);
            result = sqlSession.selectOne(this.command.getName(), param);
        }
        break;
    case FLUSH:
        result = sqlSession.flushStatements();
        break;
    default:
        throw new BindingException("Unknown execution method for: " + this.command.getName());
    }

    if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
        throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
    } else {
        return result;
    }
}

最终请求被转回SqlSession进行处理,而SqlSession底层都是依赖Executor类进行SQL操作。Executor依赖Transaction进行getConnection(持有DataSource进行连续获取MyBatis(2)-连接管理)、commit、rollback、close等事务控制,如果是JdbcTransaction则直接依赖java.sql.Connection的方法。Executor同时依赖StatementHandler调用java.sql.Statement进行SQL执行。

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;
}

缓存管理

一级缓存

默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。若设置为SESSION,同一个session内的insert/delete/update操作会令缓存失效,但另外一个session的insert/delete/update操作不会,所以会一起脏读,建议设置为STATEMENT。

<setting name="localCacheScope" value="SESSION"/>

二级缓存

利用cacheEnabled全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存,默认为true。由CachingExecutor装饰某一个其他的BaseExecutor来实现,可以在SqlSession之间共享缓存数据,但要commit之后才能生效。由于缓存是以Mapper名区分存储的,一个Mapper的更新操作不会去刷新另一个Mapper的缓存,所以多表查询时会出现脏读。

<setting name="cacheEnabled" value="true"/>

聊聊MyBatis缓存机制

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值