Mybatis source code – sqlsession access

Time:2022-5-9

preface

Known inMybatisIn useMybatisThe configuration file will be read firstmybatis-config.xmlFor character stream or byte stream, and then throughSqlSessionFactoryBuilderBuild based on the character stream or byte stream of the configuration fileSqlSessionFactory, and then passSqlSessionFactoryofopenSession()Method acquisitionSqlSession, the sample code is shown below.

public static void main(String[] args) throws Exception {
    String resource = "mybatis-config.xml";
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
            .build(Resources.getResourceAsStream(resource));
    SqlSession sqlSession = sqlSessionFactory.openSession();
}

In the above example codeSqlSessionFactoryActuallyDefaultSqlSessionFactory, this article willDefaultSqlSessionFactoryobtainSqlSessionLearn from the process.

text

DefaultSqlSessionFactoryofopenSession()The method is as follows.

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

Keep lookingopenSessionFromDataSource()The implementation of the method is as follows.

private SqlSession openSessionFromDataSource(ExecutorType execType, 
                                             TransactionIsolationLevel level, 
                                             boolean autoCommit) {
    Transaction tx = null;
    try {
        //The environment contains transaction factories and data sources
        final Environment environment = configuration.getEnvironment();
        //Get transaction factory
        //If JDBC transaction is configured, get JDBC transaction factory; otherwise, get managed transaction factory
        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
        //Create transaction
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        //Create actuator
        final Executor executor = configuration.newExecutor(tx, execType);
        //Build defaultsqlsession and return
        return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
        closeTransaction(tx);
        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

openSessionFromDataSource()The method will start withConfigurationLieutenant generalEnvironmentGet it,EnvironmentContains transaction factories and data sources,EnvironmentYesMybatisConfigure in the configuration file and loadMybatisProfile is added toConfigurationYes.MybatisTwo transaction factories can be configured in the configuration file ofJDBCTransaction factory andMANAGEDTransaction factories, which can be created separatelyJDBCTransactions andMANAGEDTransaction class diagram is shown below.

Mybatis source code - sqlsession access

Gets the name of the transaction factorygetTransactionFactoryFromEnvironment()The method is as follows.

private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {
    if (environment == null || environment.getTransactionFactory() == null) {
        //If a transaction factory is configured, the configured transaction factory is used
        //Mybatis can configure JDBC and managed transaction factories
        return new ManagedTransactionFactory();
    }
    //Use managed transaction factory without configuration
    return environment.getTransactionFactory();
}

MybatisIf used inJDBCTransaction, the management of the transaction is performed byjava.sql.ConnectionDone, if usedMANAGEDTransaction, thenMybatisThe management of the affairs will be entrusted toWEBContainer(TomcatJBossWait) to complete. withcommit()androllback()Take the method as an exampleJdbcTransactionandManagedTransactionThe implementation of these two methods is as follows.

public class JdbcTransaction implements Transaction {

    ......

    @Override
    public void commit() throws SQLException {
        if (connection != null && !connection.getAutoCommit()) {
            if (log.isDebugEnabled()) {
                log.debug("Committing JDBC Connection [" + connection + "]");
            }
            connection.commit();
        }
    }

    @Override
    public void rollback() throws SQLException {
        if (connection != null && !connection.getAutoCommit()) {
            if (log.isDebugEnabled()) {
                log.debug("Rolling back JDBC Connection [" + connection + "]");
            }
            connection.rollback();
        }
    }

    ......

}

public class ManagedTransaction implements Transaction {

    ......

    @Override
    public void commit() throws SQLException {
        //Does nothing
    }

    @Override
    public void rollback() throws SQLException {
        //Does nothing
    }

    ......

}

go back toopenSessionFromDataSource()Method. After the transaction is created, the executor will be builtExecutor, take a looknewExecutor(Transaction transaction, ExecutorType executorType)The implementation of the method is as follows.

public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    //Create an executor of the corresponding type according to the enumerated value of executortype
    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 the second level cache is enabled in the mybatis configuration file
    if (cacheEnabled) {
        //Create cacheingexecution as the decorator of the executor, and add the L2 cache function to the executor
        executor = new CachingExecutor(executor);
    }
    //Add plug-in logic to the executor
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
}

Build the actuator on itExecutorThe method mainly does three things, which are explained as follows.

First thing, according toExecutorTypeCreates an enumeration value of the corresponding typeExecutorExecutorTypeThe enumeration values are as follows.

public enum ExecutorType {
    SIMPLE, REUSE, BATCH
}

MybatisThere are three types ofExecutor, respectivelyBatchExecutorReuseExecutorandSimpleExecutor, the class diagram is shown below.

Mybatis source code - sqlsession access

stayBaseExecutorFour abstract methods are defined in, as shown below.

protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;

protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException;

protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
    throws SQLException;

protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
    throws SQLException;

BaseExecutorThese four abstract methods will be called in the provided methods, and these four abstract methods need to beBatchExecutorReuseExecutorandSimpleExecutorAccording to their respective functions, soExecutorThe design of uses the template design pattern.

The second thing, ifMybatisIf the L2 cache is enabled in the configuration file; otherwiseExecutorCreate decoratorCachingExecutorTo increase support for L2 caching.CachingExecutorAndExecutorThe relationship is as follows.

Mybatis source code - sqlsession access

CachingExecutorRealizedExecutorInterface, at the same timeCachingExecutorholdExecutorThis is the application of decorator pattern. aboutMybatisCaching in will be introduced in subsequent articles.

The third thing, if a plug-in is configured, add the logic of the plug-in to theExecutorYes. aboutMybatisThe plug-ins in will be introduced in subsequent articles.

go back toopenSessionFromDataSource()Method, create a goodExecutorAfter, theDefaultSqlSessionCreate aDefaultSqlSessionAnd return, inDefaultSqlSessionThe construction method of is only a simple assignment, as shown below.

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
    this.configuration = configuration;
    this.executor = executor;
    this.dirty = false;
    this.autoCommit = autoCommit;
}

So far,SqlSessionIt was created.

summary

SqlSessionIs obtained throughSqlSessionFactoryofopenSession()method,SqlSessionThe creation process of is mainly to create a transaction manager first, and then create an actuator based on the transaction managerExecutorFinally, based onExecutorestablishSqlSession。 Usually,SqlSessionFactorybyDefaultSqlSessionFactory, createdSqlSessionbyDefaultSqlSession

Recommended Today

How to insert an LSM tree into NVM

Introduction: with the commercial promotion of nonvolatile memory products, we are more and more interested in its large-scale promotion potential in cloud native database. X-engine is an LSM tree storage engine developed by the polardb new storage engine team of Alibaba cloud database products division. It currently provides external services on Alibaba cloud polardb products. […]