Author: Small Fuge series: bugstack.cn/md/spring/d…

Precipitation, share, grow, let yourself and others can gain something! 😄

One, foreword

How do you approach feature iterations?

In fact, many programmers do not have many opportunities to work on a new project when they just start programming or join a new company. Most of the time, they are constantly iterating on the old project. In this process, you may have to learn N different styles of code fragments left by predecessors, and find a place in the crisscrossing flow to add your own ifelse.

Although this random add ifelse, just start to “put rotten” mentality, let a person very uncomfortable. But delivering high-quality code on an already-compressed schedule is also difficult, so part of the development is forced to work and run.

However, in fact, can not gradually clean up a mountain of shit, so that the code in your hands gradually clear, neat, clean, most of the time is the lack of experience as a coder, do not know the system reconstruction, do not understand the design principles, do not know the business background, do not know the product trend and so on. So the best way is to improve their own ability, did not receive a demand for some technical changes, since it is shit mountain, it is as a dozen strange upgrade, repair a bit, change a piece, fill a piece, always in your hand more and more easy to maintain and expand.

Second, the target

In the process of gradually realizing Mybatis framework, we should first have a goal-oriented idea, that is, how to realize the core logic of Mybatis.

The goal of such an ORM framework can be simply described as providing an interface with proxy classes that parse and process SQL information (types, input parameters, output parameters, and conditions) in Mapper, an XML file. This process is to operate on the database and return the corresponding results to the interface. As shown in figure 4-1

Then according to the execution process of ORM core process, we need to continue to expand the analysis of Mapper file and extract the corresponding SQL file on the basis of the previous chapter. And at the current stage, it can meet the requirement that when we call the DAO interface method, we can return the corresponding SQL statement to be executed in Mapper. In order not to extend the whole project, small Fu Ge will lead you to gradually complete these contents, so this chapter will not operate on the database for the time being, to be followed up gradually

Three, the design

In conjunction with the previous chapter we used MapperRegistry to scan the package path to register the mapper and use it in DefaultSqlSession. So after we can unify these namespace, SQL description, mapping information into the Mapper XML file corresponding to each DAO, IN fact, XML is our source. Through the XML file parsing and processing can be completed Mapper Mapper registration and SQL management. This is also more we operate and use. As shown in figure 4-2

  • So we need to defineSqlSessionFactoryBuilderThe Factory Builder schema class parses XML files by way of entry IO. At present, we mainly parse the SQL part and register the mapper to connect the whole core process.
  • After the file is parsed, it will be stored in the Configuration class. Next you will see that this Configuration class will be connected to the whole Mybatis process. All contents are stored and read without this class. Fetching Mapper and performing selectOne in DefaultSqlSession also require reading operations in the Configuration class.

Four, implementation,

1. Engineering structure

mybatis-step-03└ ─ ─ the SRC ├ ─ ─ the main │ └ ─ ─ Java │ └ ─ ─ cn. Bugstack. Mybatis │ ├ ─ ─ binding │ │ ├ ─ ─ MapperMethod. Java │ │ ├ ─ ─ MapperProxy. Java │ │ ├ ─ ─ MapperProxyFactory. Java │ │ └ ─ ─ MapperRegistry. Java │ ├ ─ ─ builder │ │ ├ ─ ─ XML │ │ │ └ ─ ─ XMLConfigBuilder. Java │ │ ├─ ├─ Java │ ├─ Java │ ├─ Java │ ├─ Java │ ├─ Java │ ├─ Java │ ├─ Java │ ├─ Java │ ├─ SqlCommandType. Java │ └ ─ ─ the session │ ├ ─ ─ defaults │ │ ├ ─ ─ DefaultSqlSession. Java │ │ └ ─ ─ DefaultSqlSessionFactory. Java │ ├ ─ ─ Configuration. Java │ ├ ─ ─ SqlSession. Java │ ├ ─ ─ SqlSessionFactory. Java │ └ ─ ─ the SqlSessionFactoryBuilder is the Java └ ─ ─ the test ├ ─ ─ Java │ └ ─ ─ cn. Bugstack. Mybatis. Test. The dao │ ├ ─ ─ dao │ │ └ ─ ─ IUserDao. Java │ ├ ─ ─ Po │ │ └ ─ ─ User. Java │ └ ─ ─ ApiTest. Java └ ─ ─ resources ├ ─ ─ mapper │ └ ─ ─ User_Mapper. XML └ ─ ─ mybatis config - datasource. The XMLCopy the code

Project source: t.zsxq.com/bmqNFQ7

XML parsing and registering class implementation relationships, as shown in Figure 4-2

  • SqlSessionFactoryBuilder acts as an entry point to Mybatis, providing a builder factory, wrapping XML parsing, and returning the corresponding SqlSessionFactory processing class.
  • Register the XML information in the Configuration Configuration class by parsing, and pass the Configuration Configuration class to various logical processing classes, including DefaultSqlSession, so that when fetching the mapper and executing SQL, Got the corresponding content from the configuration class.

2. Build the SqlSessionFactory builder factory

Source see: cn bugstack. Mybatis. Session. The SqlSessionFactoryBuilder is

public class SqlSessionFactoryBuilder {

    public SqlSessionFactory build(Reader reader) {
        XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder(reader);
        return build(xmlConfigBuilder.parse());
    }

    public SqlSessionFactory build(Configuration config) {
        return newDefaultSqlSessionFactory(config); }}Copy the code
  • SqlSessionFactoryBuilder is an entry class to Mybatis, which directs the process by specifying IO to parse XML.
  • From this class, two new processing classes, XMLConfigBuilder and Configuration, are added to parse XML and concatenate object saving operations throughout the process, respectively. Next, we’ll look at each of these newly introduced objects.

3. XML parsing processing

Source see: cn bugstack. Mybatis. Builder. XML. XMLConfigBuilder

public class XMLConfigBuilder extends BaseBuilder {

    private Element root;

    public XMLConfigBuilder(Reader reader) {
        // 1. Invoke the parent class to initialize Configuration
        super(new Configuration());
        // 2. Dom4j handles XML
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(new InputSource(reader));
            root = document.getRootElement();
        } catch(DocumentException e) { e.printStackTrace(); }}public Configuration parse(a) {
        try {
            // Parse the mapper
            mapperElement(root.element("mappers"));
        } catch (Exception e) {
            throw new RuntimeException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
        }
        return configuration;
    }

    private void mapperElement(Element mappers) throws Exception {
        List<Element> mapperList = mappers.elements("mapper");
        for (Element e : mapperList) {
            		// Parse processing, refer to the source code
            		
                // Add parse SQL
                configuration.addMappedStatement(mappedStatement);
            }

            // Register the Mapperconfiguration.addMapper(Resources.classForName(namespace)); }}}Copy the code
  • The core operation of XMLConfigBuilder is to initialize the Configuration, which is the closest operation to parsing XML and storing it, so this is a good place to put it.
  • Parse () is then performed and the parsed information is stored in the Configuration class, including adding parse SQL and registering Mapper.
  • The parse configuration as a whole includes: type aliases, plug-ins, object factories, object wrapper factories, Settings, environments, type conversions, mapper, but we don’t need that much yet, so we just do the necessary SQL parsing.

4. Pack the registration machine and SQL statements by configuring classes

Source code can be found in the (Configuration) : cn) bugstack. Mybatis. Session. The Configuration

public class Configuration {

    /** * Map registration machine */
    protected MapperRegistry mapperRegistry = new MapperRegistry(this);

    /** * mapping statement exists in Map */
    protected final Map<String, MappedStatement> mappedStatements = new HashMap<>();

    public <T> void addMapper(Class<T> type) {
        mapperRegistry.addMapper(type);
    }

    public void addMappedStatement(MappedStatement ms) { mappedStatements.put(ms.getId(), ms); }}Copy the code

Add mapper register machine and store mapping statement in configuration class;

  • The Mapper registry is what we implemented in the previous section to register the action classes provided by the Mapper Mapper lock.
  • Another MappedStatement is a new SQL information record object added in this section, including records: SQL type, SQL statement, input parameter type, and output parameter type.Details can refer to the source code

5. DefaultSqlSession obtains information based on configuration items

Source see: cn bugstack. Mybatis. Session. Defaults. DefaultSqlSession

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    @Override
    public <T> T selectOne(String statement, Object parameter) {
        MappedStatement mappedStatement = configuration.getMappedStatement(statement);
        return (T) ("You're being represented!" + \n Method:" + statement + "\n input parameter:" + parameter + "\n SQL:" + mappedStatement.getSql());
    }

    @Override
    public <T> T getMapper(Class<T> type) {
        return configuration.getMapper(type, this); }}Copy the code
  • DefaultSqlSession is compared to the previous section, where Little Fugger puts itMapperRegistry mapperRegistryReplace withConfiguration configurationIn order to deliver richer information content than just registry operations.
  • Then we use configuration in both defaultsQlssession #selectOne and DefaultsQlssession #getMapper to get the corresponding information.
  • At present, the selectOne method only prints the obtained information, and the SQL executor will be introduced later to query and return the results.

Five, the test

1. Prepare

Provides the DAO interface and the corresponding Mapper XML configuration

public interface IUserDao {

    String queryUserInfoById(String uId);

}
Copy the code
<mapper namespace="cn.bugstack.mybatis.test.dao.IUserDao">

    <select id="queryUserInfoById" parameterType="java.lang.Long" resultType="cn.bugstack.mybatis.test.po.User">
        SELECT id, userId, userHead, createTime
        FROM user
        where id = #{id}
    </select>

</mapper>
Copy the code

Unit testing

@Test
public void test_SqlSessionFactory(a) throws IOException {
    // 1. Obtain SqlSession from SqlSessionFactory
    Reader reader = Resources.getResourceAsReader("mybatis-config-datasource.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    SqlSession sqlSession = sqlSessionFactory.openSession();

    // 2. Get the mapper object
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);

    // 3. Test validation
    String res = userDao.queryUserInfoById("10001");
    logger.info("Test result: {}", res);
}
Copy the code
  • The current approach is very similar to Mybatis: load the XML configuration file, hand it to SqlSessionFactoryBuilder for build parsing, and get the SqlSessionFactory factory. This allows the Session to be opened and the rest of the operation to be completed.

The test results

07:07:40.519[the main] INFO cn. Bugstack. Mybatis. Test. The ApiTest - test results: you have been acting! Methods: cn. Bugstack. Mybatis. Test. Dao. IUserDao. QueryUserInfoById into arguments: [Ljava. Lang. Object; @ 23223 dd8 to execute SQL:  SELECT id, userId, userHead, createTime FROM user where id = ? Process finished with exit code0
Copy the code
  • From the test results, we can see that the current agent operation has been able to print the SQL information we parsed from THE XML, and we will continue to complete the database operation combined with this part of the processing.

Six, summarized

  • Knowing the core flow of ORM processing, knowing where we are and what we are trying to accomplish, the framework can only be implemented with a clear understanding of the process of proxying, encapsulating, parsing, and returning results.
  • The introduction of SqlSessionFactoryBuilder wraps the entire execution process, including: XML file parsing, Configuration Configuration class processing, DefaultSqlSession can be more flexible to get the corresponding information, Mapper and SQL statements.
  • In addition, in the process of building the whole project, we can see that there are many factory mode, builder mode, agent mode, and many design principles. These skills can make the whole project easy to maintain and iterate.This is also research and development personnel in the process of learning the source code, it is worth focusing on the place.