mybatis源码解析-获取Sqlsession

上篇文章讲了mybatis是怎么创建SqlSessionFactory的:mybatis源码解析-SqlsessionFactory,简单来说就是通过构造模式读取xml配置文件封装到Configuration对象中,返回一个默认的DefaultSqlSessionFactory对象,需要注意的是我们写的每一个mapper映射文件在配置类中定义好了之后会被解析进Configuration中,并且mapper映射文件中的增删改查标签都有与之对应的MappedStatement对象封装,我们还是摆出hello world来演示:

//1.通过输入流解析xml配置文件
InputStream inputstream = Resources.getResourceAsStream("xxx.xml")
SqlsessionFactory sqlsessionfactory = new SqlsessionFactoryBuilder().build(inputstream);
//2.获取和数据库的链接,创建会话
SqlSession openSession = sqlsessionfactory.openSession();
//3.获取接口的实现类对象,会为接口自动的创建一个代理对象mapper,代理对象会去执行增删改查方法
xxxMapper mapper = openSession.getMapper(xxxMapper.class)
//4.执行增删改的方法

第一步已经讲过了,现在来看第二步,获取链接创建会话SqlSession

Sqlsession

1.1:直接来到sqlsessionfactory.openSession();这个方法,它其实调用的是DefaultSqlSessionFactoryopenSessionFromDataSource方法

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

在进入查看这个方法之前,this.configuration.getDefaultExecutorType()这个是选择一种执行器在这里插入图片描述
这里默认选的是SIMPLE,在mybatis官方文档有这样的三种设置:在这里插入图片描述

1.2:好了,进入openSessionFromDataSource这个方法:

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }

首先根据configuration获取当前环境,配置事务信息,Executor executor = this.configuration.newExecutor(tx, execType);这里根据我们选择的执行器类型创建执行器,进入newExecutor方法:

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

那么什么是Executor呢?请往下看:
在这里插入图片描述
这个接口里的方法就是我们执行增删改查的方法,我们继续走,在newExecutor方法中有这样一段代码:

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

它的意思是判断cacheEnabled是否开启也就是我们configuration全局配置中是否开启二级缓存,如果开启就用CachingExecutor((Executor)executor)来包装这个执行器,我们进入这个类:
1.3:我们截取一部分代码来研究:

public class CachingExecutor implements Executor {
    private final Executor delegate;
    private final TransactionalCacheManager tcm = new TransactionalCacheManager();

    public CachingExecutor(Executor delegate) {
        this.delegate = delegate;
        delegate.setExecutorWrapper(this);
    }

来看一看这个类的结构:、
在这里插入图片描述
我们可以知道,这个类将传进来的执行器包装了一下,真正执行增删改查的是他内部的Executor delegate对象,我们继续看newExecutor在最终完成并返回Executor前,还会调用这个方法:
Executor executor = (Executor)this.interceptorChain.pluginAll(executor);
就是调用拦截器链的pluginAll方法,在目前为止这个方法看起来貌似没什么作用,其实不然,在后面的插件介绍中,它就通过这种方式来包装我们的执行器,我们来看一下这个方法:

public Object pluginAll(Object target) {
        Interceptor interceptor;
        for(Iterator var2 = this.interceptors.iterator(); var2.hasNext(); target = interceptor.plugin(target)) {
            interceptor = (Interceptor)var2.next();
        }

        return target;
    }

很简单,调用所有的拦截器来对Executor进行封装,好了,到现在我们就把Executor封装完毕了,回到1.2openSessionFromDataSource这个方法:

Executor executor = this.configuration.newExecutor(tx, execType);
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
return var8;

executor传入了DefaultSqlSession中,来看一下这个类:
在这里插入图片描述
最终返回了DefaultSqlSession

总结

最后用一张图来简单回顾一下:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章