This is the seventh day of my participation in the First Challenge 2022

Introduction to the

MyBatis can connect to a Druid database in the same way as the Druid database connection pool

The source code parsing

Based on the sample code from the previous article:

public class MybatisTest {

    @Test
    public void test(a) {
        try(SqlSession session = buildSqlSessionFactory().openSession()) {
            PersonMapper personMapper = session.getMapper(PersonMapper.class);
            personMapper.createTable();
            personMapper.save(Person.builder().id(1L).name("1").build());
            Person person = personMapper.getPersonById(1); System.out.println(person); }}public static SqlSessionFactory buildSqlSessionFactory(a) {
        String JDBC_DRIVER = "org.h2.Driver";
        String DB_URL = "jdbc:h2:mem:test; DB_CLOSE_DELAY=-1";
        String USER = "sa";
        String PASS = "";
        DataSource dataSource = new PooledDataSource(JDBC_DRIVER, DB_URL, USER, PASS);
        Environment environment = new Environment("Development".new JdbcTransactionFactory(), dataSource);
        Configuration configuration = new Configuration(environment);
        configuration.addMapper(PersonMapper.class);
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        returnbuilder.build(configuration); }}Copy the code

Currently we want to find the part that connects to the database

From reading the book MyBatis3 Source Code In Depth, we know that the execution is in the Executor, and we keep track of the relevant code

After unremitting efforts to track, the following key code is obtained:

Found the key code to get the connection from Executor in the execution statement

public class SimpleExecutor extends BaseExecutor {
    private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
	// Get the database connection
        Connection connection = this.getConnection(statementLog);
        Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
        handler.parameterize(stmt);
        returnstmt; }}Copy the code

Continuing the trace, we come to the transaction manager defined in our example: JdbcTransactionFactory

public class JdbcTransaction implements Transaction {
    public Connection getConnection(a) throws SQLException {
        if (this.connection == null) {
            this.openConnection();
        }

        return this.connection;
    }

    protected void openConnection(a) throws SQLException {
        if (log.isDebugEnabled()) {
            log.debug("Opening JDBC Connection");
        }

        // Get it from DataSource
        this.connection = this.dataSource.getConnection();
        if (this.level ! =null) {
            this.connection.setTransactionIsolation(this.level.getLevel());
        }

        this.setDesiredAutoCommit(this.autoCommit); }}Copy the code

PooledDataSource = PooledDataSource = PooledDataSource = PooledDataSource = PooledDataSource

public class PooledDataSource implements DataSource {
    public Connection getConnection(a) throws SQLException {
        return this.popConnection(this.dataSource.getUsername(), this.dataSource.getPassword()).getProxyConnection();
    }

    private PooledConnection popConnection(String username, String password) throws SQLException {
        while(conn == null) {
            synchronized(this.state) {
                PoolState var10000;
                if (!this.state.idleConnections.isEmpty()) {
		    ......
                } else if (this.state.activeConnections.size() < this.poolMaximumActiveConnections) {
		    // Get the database connection pool connection
                    conn = new PooledConnection(this.dataSource.getConnection(), this);
                    if (log.isDebugEnabled()) {
                        log.debug("Created connection " + conn.getRealHashCode() + "."); }}else{... }if(conn ! =null) {... }}}... }}Copy the code

Let’s keep going:

public class UnpooledDataSource implements DataSource {
    public Connection getConnection(a) throws SQLException {
        return this.doGetConnection(this.username, this.password);
    }

    private Connection doGetConnection(String username, String password) throws SQLException {
        Properties props = new Properties();
        if (this.driverProperties ! =null) {
            props.putAll(this.driverProperties);
        }

        if(username ! =null) {
            props.setProperty("user", username);
        }

        if(password ! =null) {
            props.setProperty("password", password);
        }

        return this.doGetConnection(props);
    }

    private Connection doGetConnection(Properties properties) throws SQLException {
        this.initializeDriver();
	// See the familiar native way to get a database connection
        Connection connection = DriverManager.getConnection(this.url, properties);
        this.configureConnection(connection);
        returnconnection; }}Copy the code

Here we find the key code in the source code how to get the database connection

This is essentially an encapsulation of native database operations

Call stack review

Let’s go back and look at the class call stack in the process:

  • MybatisTest: our test code
  • MapperProxy: the proxy class of MyBatis Mapper
  • MapperMethod: related to SQL execution
  • DefaultSqlSession
  • CachingExecutor
  • BaseExecutor
  • SimpleExecutor
  • JdbcTransation
  • PooledDataSource
  • UnpooledDataSource

As you can see, the database connection is obtained from the DataSource, and the PooledDataSource is MyBatis’ own database connection pool, which uses the unpooled UnpooledDataSource

MyBatis+Druid = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource = DataSource

conclusion

MyBatis+Druid = MyBatis+Druid = MyBatis+Druid = MyBatis+Druid = MyBatis+Druid