A, introducing

In the previous article, we analyzed the source code of Executor Executor. Executor uses MappedStatement and parameters to complete the mapping of SQL parameters, SQL execution, and result set processing through certain scheduling. Executor is simply scheduling related components

In this article, we will examine the functionality of Transaction and the SqlSession component before we execute SQL

Analysis of transaction related components

2.1. Initialization of Environment

<environments> <environments> <environments> <environments> <environments> <environments> <environments> <environments> <environments> <environments> <environments> <environments> <environments> <environments> <environments> <environments>

<configuration>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC"/>
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
				<property name="url" value="jdbc:mysql://dev1-linux.pospal.cn:3306/pospal?serverTimezone=GMT%2B8&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=true&amp;allowMultiQueries=true"/>
				<property name="username" value="xxx"/>
				<property name="password" value="xxx"/>
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="mapper/CustomerMapper.xml"/>
	</mappers>
</configuration>
Copy the code

As you can see, we have a development environment configured with a datasource datasource and a transactionManager. How does this map to Java objects?

private void environmentsElement(XNode context) {
    if(context ! =null) {
        if (environment == null) {
            environment = context.getStringAttribute("default");
        }
        for (XNode child : context.getChildren()) {
            String id = child.getStringAttribute("id");
            if (isSpecifiedEnvironment(id)) {
                TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
                DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
                DataSource dataSource = dsFactory.getDataSource();
                Environment.Builder environmentBuilder = newEnvironment.Builder(id) .transactionFactory(txFactory) .dataSource(dataSource); configuration.setEnvironment(environmentBuilder.build()); }}}}Copy the code

The transactionManager is mapped to a TransactionFactory, the dataSource is mapped to a DataSourceFactory, and the factory class produces factory objects, Finally, put the TransactionFactory and the produced DataSource into the Environment, and then put the Environment into the Configuration object

2.2 TransactionFactory system analysis

The JdbcTransactionFactory is created based on the JDBC in Type when parsing transactionManager. (The Configuration constructor is available for those interested. JdbcTransactionFactory (JDBC, JdbcTransactionFactory, JdbcTransactionFactory) SpringManagedTransactionFactory are introduced mybatis – spring package after the new, and mybatis actually bring only two: JdbcTransactionFactory, ManagedTransactionFactory

public interface TransactionFactory {
  void setProperties(Properties props);
  Transaction newTransaction(Connection conn);
  Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
Copy the code

The TransactionFactory interface provides the creation of the transaction object, setProperties used to pass the relevant properties of Mybatis into the factory object, if it is their own implementation of the factory object, then you can receive this property object and save. These properties can then be used when creating transactions

NewTransaction provides two overloads. One is to create a transaction object using a Connection object. The other is to create a transaction object based on the Datasource Datasource. So the TransactionFactory is basically the factory class of the transaction object that creates the transaction object from the incoming data source or connection object

JdbcTransactionFactory is a standard transaction factory class should create a standard transaction object, it is using to connect to the transaction, ManagedTransactionFactory is an extension of the mybatis provides, for the transaction to the container to manage, According to Javadoc: a Transaction that lets the container manage the entire lifecycle of a Transaction. Delay connection retrieval until getConnection() is called, ignoring all commit or rollback requests. It closes connections by default, but can be configured not to do so

SpringManagedTransactionFactory mybatis spring integration is used to complete the transaction object is created

2.3 Transaction System analysis

Three transaction factory to create different transaction object, create JdbcTransaction JdbcTransactionFactory, create ManagedTransaction ManagedTransactionFactory, Create SpringManagedTransaction SpringManagedTransactionFactory, there are three implementation class, so the Transaction interface is also its UML diagram below

public interface Transaction {
  Connection getConnection(a) throws SQLException;

  void commit(a) throws SQLException;

  void rollback(a) throws SQLException;

  void close(a) throws SQLException;

  Integer getTimeout(a) throws SQLException;
}
Copy the code

A Transaction object provides interfaces for obtaining a connection, committing a Transaction, rolling back a Transaction, closing a connection, and obtaining a Transaction timeout. Subclasses implement these interfaces. The getConnection method uses the Datasource object to create a database connection, and all the other methods operate on that connection

JdbcTransaction = JdbcTransaction = JdbcTransaction = JdbcTransaction = JdbcTransaction = JdbcTransaction

Create SqlSession

public static void main(String[] args) {
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                                .build(Resources.getResourceAsStream( "mybatis-con.xml")); SqlSession sqlSession = sqlSessionFactory.openSession(); }public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
    return build(parser.parse());
}

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}
Copy the code

The build method creates an XML configuration file parser called XMLConfigBuilder. The parse method is what we analyzed in the first article. The parse method returns a parsed Configuration object, which is then used to create the DefaultSqlSessionFactory

Create SqlSession with DefaultSqlSessionFactory openSession method

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

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    final Environment environment = configuration.getEnvironment();
    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
    Transaction tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
    final Executor executor = configuration.newExecutor(tx, execType);
    return new DefaultSqlSession(configuration, executor, autoCommit);
}
Copy the code

Mysql > create DefaultSqlSession using Configuration, Executor, mybatis (mybatis) However, the Executor needs to receive the MappedStatement object when executing SQL. This object needs to be retrieved by the NAMespance + SQL tag ID. The Executor cannot retrieve the MappedStatement object. Namespance + SQL tag id is mybatis open to the framework user connection entrance, using namespance + SQL tag ID framework user can clearly know what to execute SQL

Therefore, an interface layer is required to connect the framework user and mybatis internal executer. This interface is SqlSession:

List<Object> objectList = sqlSession.selectList("com.fightzhong.mapper.CustomerMapper.selectRemarksById".1);
public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
}

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    MappedStatement ms = configuration.getMappedStatement(statement);
    return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
}
Copy the code

In the previous article, we introduced the above SQL, and checked the data from the customer table according to the ID. The first parameter of the selectList is composed of the namespace in the Mapper file and the ID in the SQL tag. Each SQL tag is stored in a Map in the form of a key and value. The key is the ID of a NAMESPACE and the value is the Java object representation of the SQL tag, MappedStatement. Therefore, SqlSession needs to provide the corresponding database operation interface, receive a string and SQL parameters, internally use the key represented by the string, get the MappedStatement object from the Map, and then call Executor to execute the SQL and get the return value. SqlSession shields Executor and MappedStatement objects, exposing only the parameters of the framework’s consumer relationship

Go back to the code above, get the Environment object from the configuration file (save the Datasource and TransactionFactory), get the TransactionFactory from the Environment object, If it is only in mybatis environment TransactionFactory JdbcTransactionFactory, if they are in a spring environment, is getting SpringManagedTransactionFactory

Using the Transaction factory class and the data source object to create the Transaction object Transaction, then using the Transaction object to create the Executor, finally using the Executor to create DefaultSqlSession, A Transaction object has its own unique Connection object, so the SqlSession and Connection object are also one-to-one correspondence. So a SQLSession is also expected to execute in a single thread, and calling sqlSession’s close method actually closes the database connection

SqlSession is a session that is bound to a database connection and is expected to execute in a single thread. A session creates a corresponding Executor Executor that contains a Transaction object that corresponds to a unique database connection. In the execution of SQL is the use of this database connection, SqlSession is also the interface layer, used to frame users and Mybatis internal through the bridge, external through exposed to frame users through the form of string to represent the execution of the corresponding SQL, Internally, the string is used to find the corresponding MappedStatement object, and the Executor Executor is used to perform database operations

Four, Spring integration Mybatis simple analysis

In order to control the connection of mybatis to the SQL database, Spring needs to start with the Transaction object. Since Transaction is used to fetch connections and execute SQL in Executor, Spring extends the Transaction factory object. Create a SpringManagedTransaction object using the transaction factory object you implement

In Spring, every time SQL is executed in a single thread, a SqlSession is created. This SqlSession is usually created before the Mapper method is executed. However, if a transaction exists, it is created when the transaction is started. This session is used by the entire thread executing the SQL. Spring manages transactions and connection objects through SpringManagedTransaction when the session is created. SpringManagedTransaction is used to complete the spring mybatis transaction. We will analyze this section in detail when we analyze the principle of Spring transaction. This is just an introduction to the SpringManagedTransaction object mentioned above

Five, the summary

SqlSession is the interface layer, which exposes the implementation of the namespace + SQL tag ID to execute SQL and obtain the return value, and internally uses the NAMESPACE + SQL tag ID to obtain the MappedStatement object. The Executor object is then used to execute the SQL

SqlSession is also a session that is bound to a unique database Connection. In Spring, a SqlSession is created each time before Mapper is executed, and the Connection object is also new. In the case of transactions, a transaction requires a connection to run through all SQL operations, so a SqlSession is created when the transaction starts. All subsequent database operations use this session, rather than creating a new one. We will analyze the source code for specific integration later