Analysis of the implementation process and principle of the ORM of Mybatis


Article directory

Preface

Go back to basics. Today, let's see the execution process of mybatis.

First case

1, The first is the configuration file. You need an xml configuration file

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <typeAliases>  <!--Configure alias of entity class-->
        <package name="cn.itcast.orm.entity"/>
    </typeAliases>

    <environments default="MySQLDevelopment">
        <environment id="MySQLDevelopment">
            <transactionManager type="JDBC"></transactionManager> <!--affair-->
            <dataSource type="POOLED">  <!--Database connection-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/demo?characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <package name="fast.cloud.nacos.mybatis.mapper"/>
    </mappers>

</configuration>

2, Mapper and entity are defined. The detailed code is in https://github.com/fafeidou/fast-cloud-nacos/tree/master/fast-source-code-analysis/code-mybatis

3, Query as follows

@Test
    public void testMybatis() throws IOException {
        //1. Load core configuration file
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");

        //2. Parse core configuration file and create SqlSessionFactory object
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);

        //3. Create core objects
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //4. Get Mapper proxy object
        DeptEmpMapper deptEmpMapper = sqlSession.getMapper(DeptEmpMapper.class);

        //5. Call the user-defined method to realize the query function
        List<DeptEmp> list = deptEmpMapper.getEmpTotalByDept();
        for (DeptEmp de : list) {
            System.out.println(de);
        }

        //6. Close sqlSession
        sqlSession.close();

    }

Stepwise analysis

I think it's a way of interrupting, step by step, to see mybatis orm

  1. Parse MyBatis core configuration file and create SqlSessionFactory object
//1. Load core configuration file
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");

//2. Parse core configuration file and create SqlSessionFactory object
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);

These three lines of code first create the SqlSessionFactoryBuilder object, and then get the input stream of the MyBatis core configuration file. Finally, we call the build method, and we will follow the source code of the method.

The 77th line of code creates an xml parser object, and analyzes the MyBatis core configuration file in the 78th line, obtains the database connection data and the data in the mapping configuration file (including the sql statement and the customized resultMap we wrote), the parse method of XMLConfigBuilder, and parses the xml configuration into java objects.


Xmlconfigbuilder? Environmentslelement setting data source and transaction manager

Observe the configuration object. At this time, you can see that the data source has been initialized and the mapper has been scanned.

And the method in mapper

And the resultMap map

In the construction method of DefaultSqlSessionFactory, we found that the data obtained after analysis was finally stored in an object named Configuration, from which many subsequent operations will obtain data.

SqlSession sqlSession = sqlSessionFactory.openSession();


In the red box part of the code in the figure, the Environment object, transaction object and Executor object are created respectively by reading the data in the Configuration object, and finally a DefaultSqlSession object (implementation class of SqlSession interface) is directly new, which is the core object of MyBatis API.

DeptEmpMapper deptEmpMapper = sqlSession.getMapper(DeptEmpMapper.class);


Finally, the getMapper method of MapperRegistry object is called, and the entity class and sqlSession object are passed.


Line 50 finally creates the proxy object of our custom Mapper interface through the proxy factory.

List<DeptEmp> list = deptEmpMapper.getEmpTotalByDept();

When we call the getEmpTotalByDept() method of the proxy object, the invoke method of MapperProxy will be called inside the framework. We can observe the values of the three parameters of this method, as shown in the following figure

Lock the 53rd line of code in the invoke method, which calls the execute method of MapperMethod to realize the query function.

In the execute method, add, delete, modify, check and judge first. In this case, query is carried out, and multiple records may be found, so the 68th line of code is locked at last, and the code calls the executeForMany method to query.

Line 124 uses the hasRowBounds() method to determine whether to perform paging query. This case does not need it. So execute the code in else and call the selectList method of sqlSession (line 128). The parameter values are as shown in the following figure:

The code in line 147 obtains the MappedStatement object from the Configuration object, which stores all the information in the mapping Configuration file (including the sql statement we wrote and the custom resultMap), as shown in the following figure:

Line 124 calls the query( )Method, continue to follow.


Line 81 obtains the sql statement from the mapper mapping configuration file through the ms object, as shown in the following figure. Line 93 calls the following query method, which first fetches data from the cache internally. If there is no data in the cache, query again (line 87), and continue to follow.


If there is no data in the cache, you can query the queryFromDatabase of baseexecutor ා query, which is to get data from the database.

Finally, the sql statement is executed and the query results are encapsulated according to our customized resultMap, as shown in the following figure

80 original articles published, 78 praised, 10000 visitors+
Private letter follow

Tags: Mybatis xml SQL JDBC

Posted on Sat, 18 Jan 2020 07:05:31 -0500 by gromer