Complete solution of mybatis series (1): a persistence layer framework

Time:2021-2-19

Cover: Luo Xiaoxi
Author: Pan Pan

Complete solution of mybatis series (1): a persistence layer framework

After graduation, I started my own business first and then went to work. After nearly eight years of ups and downs, I was really anxious. Although I had been following the discipline and class route, I still didn’t settle down to study, think and comb on the technical road. When the opportunity came, I grasped it.

I hope that the knowledge recorded by myself can be of some help to later learners.

If you have any suggestions or opinions on the content of the article, or hope to exchange and learn about Internet development, or simply love life, please feel free to wechat me: panshenlian.

Complete solution of mybatis series (1): a persistence layer framework

The first series of articles mainly focus onArchitect (Java) technology line“Start chatting and update from time to time.

First, I’ll take it as an example《A persistence layer framework》Let’s make a sample first. In this article, we won’t introduce mybatis or analyze the source code. Let’s talk about a Java API:JDBC

JDBCI’m an old friend of Java. Let’s get to know him again, find out his faults, and give him some optimization suggestions from the perspective of an old friend of Java《Custom persistence layer framework》。

reminder:

If you have questions about some solutions in the process of reading, I suggest you read them with questions and digest them, because the tutors did analyze them by studying the source code of persistence layer framework such as mybatis.

In short, “big factories all write like this, let’s follow.”.

Complete solution of mybaits series (continuous update)

  • Complete solution of mybatis series (1): a persistence layer framework
  • Complete solution of mybatis series (2): introduction to mybatis and environment construction
  • Complete solution of mybatis series (3): introduction to mybatis CRUD
  • Mybatis series complete solution (4): the most complete network! Detailed explanation of mybatis configuration file XML
  • Mybatis series (5): the most complete network! Detailed explanation of mapper mapping file of mybatis
  • Complete solution of mybatis series (6): how many of the most hard core API of mybatis do you know?
  • The complete solution of mybatis series (7): the traditional way and proxy way of Dao layer from the perspective of holography
  • Complete solution of mybatis series (8): dynamic SQL of mybatis
  • Complete solutions of mybatis series (9): complex mappings of mybatis
  • Complete solution of mybatis series (10): development of mybatis annotation
  • Complete solution of mybatis series (11): complete solution of mybatis cache
  • Mybatis plug in development
  • Complete solution of mybatis series (13): mybatis code generator
  • Complete solution of mybatis series (14): Spring integrates mybatis
  • Complete solution of mybatis series (15): integration of springboot and mybatis
  • Mybatis series complete solution (16): mybatis source code analysis

1、 Who is JDBC?

Complete solution of mybatis series (1): a persistence layer framework

Who is JDBC? who are you? How good is it? See what friends on the Internet say.

Java database connectivity (JDBC) is an application program interface used in Java language to regulate how the client program accesses the database. It provides methods such as querying and updating the data in the database.

–From Baidu Encyclopedia

JDBC (Java database connectivity) is a Java API for executing SQL statements, which can provide unified access for a variety of relational databases. It consists of a group of classes and interfaces written in Java language. JDBC provides a benchmark for building more advanced tools and interfaces to enable database developers to write database applications.

–From 360 Encyclopedia

… can’t access this site

–From Wikipedia

The above is the general introduction of JDBC, the official and rigorous saying, that’s it. Let’s take a look at its highlight moment.

Since the Java language was officially announced in May 1995, Java has become popular all over the world. There are a large number of programs written in Java language, including database applications. Because there is no API of Java language, programmers have to add ODBC function call of C language into Java program. This makes many excellent features of Java unable to give full play, such as platform independence, object-oriented features and so on. As more and more programmers love the Java language, more and more companies invest more and more energy in the development of Java programs, and the requirement of accessing database API of Java language interface is more and more intense. Due to the shortcomings of ODBC, such as it is not easy to use, no object-oriented features, etc., Sun company decided to develop a database application development interface with Java language as the interface. In jdk1. X version, JDBC is only an optional part. When JDK1.1 is released, SQL class package (that is, JDBC API) will become a standard part of Java language.

Later, from JDBC 1.0 to JDBC 4.0, all the way.

–From the Internet

Combined with the introduction to deepen our understanding of JDBC.

But I want to know how he usually works? A picture《Basic architecture of JDBC》Find out:

Complete solution of mybatis series (1): a persistence layer framework

With JDBC, it is easy to send SQL statements to various relational databases.

In other words, with JDBC API, there is no need to write a program for accessing Sybase database, another program for accessing Oracle database, or another program for accessing MySQL database. Programmers only need to write a program with JDBC API, which can send SQL calls to the corresponding database.

At the same time, the combination of Java language and JDBC makes it unnecessary for programmers to write different applications for different platforms. They only need to write a program once to make it run on any platform. This is also the advantage of Java language “write once, run everywhere”.

Let’s look at the details of his work.

After all, someone once said: if you want to know a person, you have to understand TA’s work carefully.

Complete solution of mybatis series (1): a persistence layer framework

2、 How does JDBC work?


The JDBC API allows applications to access any form of tabular data, especially data stored in relational databases.
The implementation process is mainly divided into three steps
  • Connect to the data source.
  • Pass query and update instructions to the database.
  • Process the database response and return the result.
But in fact, every step of the process has special details:

Complete solution of mybatis series (1): a persistence layer framework

Usage process (detailed description)

1. Loading database driver:

Used in the program Class.forName (‘driver ‘) loads the driver. The JVM will find and load the specified driver class, and execute the static code segment of the driver class. Before JDK1.6, the JDBC specification explicitly requires that every family must register the instance with the drivermanager in the static code segment when implementing the driver class. After JDK1.6, the driver class implemented by every family no longer needs to register the instance actively, because drivermanager R has been implemented in all jar packages in the initialization phase java.sql.Driver Class and initialize it.

  1. To create a database connection:

Drivermanager tries to get the connection by traversing all registered drivers. The first match will be returned directly, and the corresponding driver will be used to establish the network connection between the client and the database server (see the physical connection socket).

  1. To create a compilation object:

After the database connection is successful, we will send a request (statement) to the database and execute an SQL statement. A connection can execute multiple statements unless you close the connection. Another concept is transaction. Transaction and request can be one-to-one or one to many, depending on whether you want to use multiple request statements as the database connection The same transaction is submitted once, or a request is submitted once. JDBC default is that the transaction is automatically submitted, that is, auto commit is open, so the default is one-to-one.

  1. Set input parameters to execute SQL:

In order to prevent SQL injection, we use preprocessing in SQL to use? As a place holder for input parameters. After compiling, SQL becomes a safe SQL statement and then queries (we can talk about why preprocessing mechanism can prevent SQL injection).

  1. Encapsulate the returned result set:

After SQL execution, the result set will be encapsulated into the resultset class. The position of the initial number of lines of the iterator of the resultset class itself is 1. Therefore, we will find that java.util.Iterator The initial number of iterations of the interface is 0, which is different. At the same time, the resultset class itself does not provide the hasnext method, so we will continue to run while( rs.next ()) and then read the number through different types of accessors Data (such as getString, getinteger, etc.).

  1. Release database connection resources:

Considering that the database connection takes up the memory resources of the database server, it is impossible to establish the connection without limit, release it when it is used up, and form a good habit. At present, many mature data connection pool technologies are good at optimizing the management of data connection.

Let’s demonstrate the process through a simple example. This example uses JDBC to operate MySQL database. Let’s first take a look at our final project structure and the application of JDBC API in JDK rt.jar The structure of the system is as follows
  • Project structure:

Complete solution of mybatis series (1): a persistence layer framework

  • Application of JDBC API in JDK rt.jar The structure of the system is as follows

Complete solution of mybatis series (1): a persistence layer framework

By default, it has java development environment and MySQL database

  1. Create a mave project and introduce MySQL driver dependency

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.25</version>
    </dependency>
</dependencies>
  1. Create java test class
package com.panshenlian.jdbc;

import com.panshenlian.po.User;

import java.sql.*;

/**
 * @Author: panshenlian
 *@ Description: demonstrates how to connect to MySQL database through JDBC
 * @Date: Create in 20:11 2020/11/10
 */
public class Test01 {

    public static void main(String[] args) {
        User user = new User();
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //Load database driver
            Class.forName("com.mysql.jdbc.Driver");
            //Get database connection through driver management class
            connection = 
               DriverManager.getConnection(
                  "jdbc:mysql://localhost:3306/mybatis"+
                  "?characterEncoding=utf-8",
                  "root","123456");
            //Define SQL statements? Represents a placeholder
            String sql = " select * from user where username = ? ";
            //Gets the preprocessing statement object
            preparedStatement = connection.prepareStatement(sql);
            //Setting parameters
            //The sequence number of the parameter in the first parameter SQL statement (starting from 1)
            //The second parameter is the set parameter value
            preparedStatement.setString(1,"panshenlian");
            //Send SQL to the database to execute the query and find out the result set
            resultSet = preparedStatement.executeQuery();
            //Traversing query result set
            while(resultSet.next()){
                int id = resultSet.getInt("id");
                String name = resultSet.getString("username");
                //Encapsulating user
                user.setId(id);
                user.setUserName(name);
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //Release resources
           if(resultSet!=null){
               try {
                   resultSet.close();
               } catch (SQLException e) {
                   e.printStackTrace();
               }
           }
          if(preparedStatement!=null){
              try {
                  preparedStatement.close();
              } catch (SQLException e) {
                  e.printStackTrace();
              }
          }
          if(connection!=null){
              try {
                  connection.close();
              } catch (SQLException e) {
                  e.printStackTrace();
              }
           }
        }
    }
}
  1. Create a user class
package com.panshenlian.po;

/**
 * @Author: panshenlian
 *@ Description: user entity
 * @Date: Create in 20:10 2020/11/10
 */
public class User {

    private  Integer id;
    private String userName;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                '}';
    }
}
  1. Create SQL statement

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `birthday` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'senly', '123', '2020-11-10');
INSERT INTO `user` VALUES ('2', 'panshenlian', '123456', '2020-11-10');
  1. Execution result, nice, successful.

User{id=2, userName='panshenlian'}

After watching this demonstration, do you find a problem? The whole process of using JDBC database is cumbersome and awkward, just like this conversation:

Complete solution of mybatis series (1): a persistence layer framework

Well You’re really bored with JDBC.

I understand that you need to establish a connection with the database, execute SQL statements, and process the query result set

But can the whole process be optimized?

3、 What should be optimized in JDBC?


We usually lose weight and increase muscle, and we have to improve the quality and efficiency of our work

//Load database driver
Class.forName("com.mysql.jdbc.Driver");
//Get database link through driver management class
connection = DriverManager.getConnection(
    "jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8",
    "root","123456");
  • Problem 1: database configuration information existsHard codingQuestions.

    Optimization idea: use configuration file!

  • Problem 2: frequent creation and releaseDatabase connectionQuestions.

    Optimization idea: use data connection pool!

//Define SQL statements? Represents a placeholder
 String sql = " select * from user where username = ? ";
 //Gets the preprocessing statement object
 preparedStatement = connection.prepareStatement(sql);
 //The first parameter is the sequence number of the parameter in the SQL statement (starting from 1), and the second parameter is the set parameter value
 preparedStatement.setString(1,"tom");
 //Send SQL to the database to execute the query and find out the result set
 resultSet = preparedStatement.executeQuery();
  • Problem 3: SQL statement, setting parameters and getting result set parameters all existHard codingQuestions.

    Optimization idea: use configuration file!

//Traversing query result set
while(resultSet.next()){
   int id = resultSet.getInt("id");
   String userName = resultSet.getString("username");
   //Encapsulating user
   user.setId(id);
   user.setUserName(userName);
   System.out.println(user);
}
  • There are four problemsManual encapsulationIt is tedious to return the result set.

    Optimization idea: use java reflection, introspection!

In view of the deficiencies in all aspects of JDBC, we have sorted out the corresponding optimization ideas and summarized them in a unified way

Existing problems Optimization ideas
The database configuration information is hard coded Use profile
Frequent creation and release of database connections Using data connection pool
There are hard coding problems in SQL statements, setting parameters and getting result set parameters Use profile
Manually encapsulating the returned result set is cumbersome Reflection and introspection with Java

If you are asked to optimize, how would you design a persistence layer framework based on these optimization ideas?

4、 Custom persistence layer framework: Thinking Analysis


JDBC is a personal operation, doing everything by oneself, low efficiency and high risk, self loading drive, self building connection, self

The persistence layer framework is similar to the cooperation of multiple types of work, with clear division of labor and efficient execution. There are those who are specially responsible for resolving the registration driver to establish connections, those who are specially responsible for managing the data connection pool, those who are specially responsible for executing SQL statements, those who are specially responsible for preprocessing parameters, and those who are specially responsible for assembling result sets

The role of the framework is to help us reduce the heavy development details and redundant code, so that we can focus more on business application development.
Let’s see the difference between using JDBC and using persistence layer framework?
How comfortable is it for our users (mainly R & D personnel) to use the framework?

Complete solution of mybatis series (1): a persistence layer framework

Is it so comfortable to have such a persistence layer framework that we only need to do two things:

  • Configure data sources(address / data name / user name / password)
  • Writing SQL and parameter preparation(SQL statement / parameter type / return value type)
In addition to considering its own engineering design, the framework also needs to consider the use scenarios of the actual project end
  • User side (actual project)
  • Persistence layer framework itself

The above two steps, we through a structure diagram《Basic idea of handwriting persistence layer framework》To sort out clearly:

Complete solution of mybatis series (1): a persistence layer framework

Key description of core interface / class:
Division and cooperation Role orientation Class name definition
Responsible for reading configuration files Resource support Resources
Responsible for storing database connection information Database resource class Configuration
Responsible for storing SQL mapping definition and result set mapping definition SQL and result set resource class MappedStatement
Responsible for parsing configuration files and creating session factory sqlsessionfactory Session factory builder SqlSessionFactoryBuilder
Responsible for creating session sqlsession Conversation factory SqlSessionFactory
Assign executor conversation SqlSession
Responsible for executing SQL (with the specified resource mapped statement) Actuator Executor

Normally, the project only corresponds to a set of database environment, and generally corresponds to a sqlsessionfactory instance object. We use singleton mode to create only one sqlsessionfactory instance.

If you need to configure multiple sets of database environment, you need to do some expansion. For example, mybatis can support multiple sets of test / production database environment switching through the configuration of environments.

After sorting out the basic ideas of the persistence layer framework and clarifying the role division of the framework, we start to sort out the detailed scheme

A. The user side of the project calls the framework API. In addition to introducing the jar package of the persistence layer framework, it also needs to provide two additional parts of configuration information:

one sqlMapConfig.xml  : database configuration information (address / data name / user name / password), and mapper.xml The whole path of.
 two mapper.xml  : SQL configuration information, storing SQL statements, parameter types, return value type related information.

B. The framework itself, in essence, encapsulates JDBC code. There are six basic steps

  1. Load configuration file: according to the path of configuration file, load configuration file into byte input stream and store it in memory.
Create a resource class and provide the method of loading stream: InputStream getresourceasstream (string path)
  1. Create two JavaBeans (container objects): store the content parsed by the configuration file
Configuration (core configuration class): store sqlMapConfig.xml The content of the analysis.
 Mappedstatement (mapping configuration class): storing mapper.xml The content of the analysis.
  1. Parse the configuration file (using Dom4j) and create a sqlsession session object
Create class: sqlsessionfactorybuilder method: build (InputStream in)
 >Use Dom4j to parse the configuration file and encapsulate the parsed content into the container object
 >Create sqlsessionfactory object and produce sqlsession session object (factory mode)
  1. Create the sqlsessionfactory interface and implement the class defaultsqlsessionfactory
Create opensession () interface method to produce sqlsession
  1. Create the sqlsession interface and implement the class defaultsqlsession
Define CRUD operations on the database:
  > selectList();
  > selectOne();
  > update();
  > delete();
  1. Create the executor interface and implement the simpleexecution class
Create query (configuration conf, mappedstatement MS, object... Params)
  The actual execution is JDBC code.

The basic process is clear. Let’s refine the class diagram to help us code better

Simple version

Complete solution of mybatis series (1): a persistence layer framework

Detailed Edition

Complete solution of mybatis series (1): a persistence layer framework

The final persistence layer frame structure reference:

Complete solution of mybatis series (1): a persistence layer framework

Package interface class description
  • Config package
Interface / class effect
BoundSql Save the object of SQL statement, replace SQL # {} as? Sign, and store the parameter name corresponding to # {}
XMLConfigBuilder SqlMapConfig.xml Profile resolution tool class
XMLMapperBuilder Mapper.xml Profile resolution tool class
  • iopackage
Interface / class effect
Resource read SqlMapConfig.xml and Mapper.xml To input stream InputStream
  • pojopackage
Interface / class effect
Configuration encapsulation SqlMapConfig.xml configuration parameter
MappedStatement encapsulation Mapper.xml Configured SQL parameters
  • sqlSessionpackage
Interface / class effect
SqlSessionFactoryBuilder Sqlsessionfactory builder class
SqlSessionFactory Factory interface for producing sqlsession
DefaultSqlSessionFactory The default implementation class of sqlsessionfactory
SqlSession The sqlsession interface defines the basic crud method of the database
DefaultSqlSession Implementation class of sqlsession
Executor Executor interface is the real executor of SQL, using JDBC to operate database
SimpleExecutor Implementation class of executor
  • utils
Interface / class effect
ParameterMapping It comes from the mybatis framework, the SQL parameter mapping class, and stores the parameter names in # {}, ${}
TokenHandler From the mybatis framework, mark the processor interface
ParameterMappingTokenHandler From the mybatis framework, mark the processor implementation class, and parse # {}, ${} into?
GenericTokenParser It comes from mybatis framework, general tag parser, and marks # {and} to start and end processing

5、 Custom persistence layer framework: coding


Combined with UML diagram and project structure diagram, there is something in my mind. Let’s start the boring coding process.

Framework dependency pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.panshenlian</groupId>
    <artifactId>MyPersistence</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <! -- dependencies required by persistence layer framework -- >
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.17</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.1.6</version>
        </dependency>
    </dependencies>

</project>

Boundsql class under config package

package com.panshenlian.config;

import com.panshenlian.utils.ParameterMapping;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: panshenlian
 *@ Description: SQL general configuration class
 * @Date: Create in 16:12 2020/11/12
 */
public class BoundSql {

    /**
     *Parsed SQL statements
     */
    private String sqlText;

    private List<ParameterMapping> parameterMappingList =
            new ArrayList<ParameterMapping>();

    public BoundSql(String sqlText, List<ParameterMapping> parameterMappingList) {
        this.sqlText = sqlText;
        this.parameterMappingList = parameterMappingList;
    }

    public String getSqlText() {
        return sqlText;
    }

    public void setSqlText(String sqlText) {
        this.sqlText = sqlText;
    }

    public List<ParameterMapping> getParameterMappingList() {
        return parameterMappingList;
    }

    public void setParameterMappingList(List<ParameterMapping> parameterMappingList) {
        this.parameterMappingList = parameterMappingList;
    }
}

Xmlconfigbuilder class under config package

package com.panshenlian.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.panshenlian.io.Resource;
import com.panshenlian.pojo.Configuration;
import com.sun.javafx.scene.control.skin.EmbeddedTextContextMenuContent;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.List;
import java.util.Properties;

/**
 * @Author: panshenlian
 *@ Description: database configuration information parsing class
 * @Date: Create in 13:56 2020/11/12
 */
public class XMLConfigBuilder {

    private Configuration configuration;

    public XMLConfigBuilder() {
        this.configuration = new Configuration();
    }

    public Configuration parseConfig(InputStream inputStream) throws Exception {

        Document document = new SAXReader().read(inputStream);
        Element configurationRootElement = document.getRootElement();

        //Analysis of parameter information under datasource configuration
        List<Element> elementList = configurationRootElement.selectNodes("//property");
        Properties properties = new Properties();
        for (Element element : elementList){
            String name = element.attributeValue("name");
            String value = element.attributeValue("value");
            properties.put(name,value);
        }

        //Using c3p0 data source
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass(properties.getProperty("driverClass"));
        dataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
        dataSource.setUser(properties.getProperty("userName"));
        dataSource.setPassword(properties.getProperty("password"));

        //Set data source
        configuration.setDataSource(dataSource);

        //Analysis mapper.xml Read the byte input stream according to the path, and use Dom4j to parse
        List<Element> mapperElementList = configurationRootElement.selectNodes("//mapper");
        for (Element element : mapperElementList) {
            String mapperPath = element.attributeValue("resource");
            InputStream resourceAsStream = Resource.getResourceAsStream(mapperPath);
            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(configuration);
            xmlMapperBuilder.parseMapper(resourceAsStream);
        }

        return configuration;
    }
}

Xmlmapperbuilder class under config package

package com.panshenlian.config;

import com.panshenlian.pojo.Configuration;
import com.panshenlian.pojo.MappedStatement;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.List;

/**
 * @Author: panshenlian
 *@ Description: SQL configuration information parsing class
 * @Date: Create in 14:28 2020/11/12
 */
public class XMLMapperBuilder {

    private Configuration configuration;

    public XMLMapperBuilder(Configuration configuration) {
        this.configuration = configuration;
    }

    public void parseMapper(InputStream inputStream) throws DocumentException {

        Document mapperDocument = new SAXReader().read(inputStream);
        Element rootElement = mapperDocument.getRootElement();
        String namespace = rootElement.attributeValue("namespace");

        //Parse each select node
        List<Element> selectNodes = mapperDocument.selectNodes("//select");
        for (Element element : selectNodes) {
            String id = element.attributeValue("id");
            String resultType = element.attributeValue("resultType");
            String parameterType = element.attributeValue("parameterType");
            String sql = element.getTextTrim();

            //Parsing and encapsulating into mapperdstatement object
            MappedStatement mappedStatement = new MappedStatement();
            mappedStatement.setId(id);
            mappedStatement.setResultType(resultType);
            mappedStatement.setParameterType(parameterType);
            mappedStatement.setSql(sql);
            String statementId = namespace + "." + id;
            configuration.getMappedStatementMap().put(statementId,mappedStatement);
        }

    }
}

Resource tool class under IO package

package com.panshenlian.io;

import java.io.InputStream;

/**
 * @Author: panshenlian
 *@ Description: resource class
 * @Date: Create in 9:22 2020/11/12
 */
public class Resource {

    /**
     *According to the path of configuration file, the configuration file is loaded into byte input stream and stored in memory
     * @param path
     * @return
     */
    public static InputStream getResourceAsStream(String path){
        InputStream inputStream = Resource.class.getClassLoader().getResourceAsStream(path);
        return inputStream;
    }

}

Configuration under POJO package

package com.panshenlian.pojo;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: panshenlian
 *@ Description: database configuration class
 * @Date: Create in 13:58 2020/11/12
 */
public class Configuration {

    private DataSource dataSource;

    /**
     * key:statementId
     *Value: encapsulated mappedstatement object
     */
    private Map<String,MappedStatement> mappedStatementMap = new HashMap<String, MappedStatement>();

    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public Map<String, MappedStatement> getMappedStatementMap() {
        return mappedStatementMap;
    }

    public void setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) {
        this.mappedStatementMap = mappedStatementMap;
    }
}

Mappedstatement in POJO package

package com.panshenlian.pojo;

/**
 * @Author: panshenlian
 *@ Description: SQL and result set resource class (responsible for storing SQL mapping definition and result set mapping definition)
 * @Date: Create in 14:17 2020/11/12
 */
public class MappedStatement {

    /**
     *ID identification
     */
    private String id;

    /**
     *Return value type
     */
    private String resultType;

    /**
     *Parameter value type
     */
    private String parameterType;

    /**
     *SQL statement
     */
    private String sql;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getResultType() {
        return resultType;
    }

    public void setResultType(String resultType) {
        this.resultType = resultType;
    }

    public String getParameterType() {
        return parameterType;
    }

    public void setParameterType(String parameterType) {
        this.parameterType = parameterType;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }
}

Default sqlsession under sqlsession package

package com.panshenlian.sqlSession;

import com.panshenlian.pojo.Configuration;
import com.panshenlian.pojo.MappedStatement;

import java.lang.reflect.*;
import java.util.List;

/**
 * @Author: panshenlian
 *@ Description: SQL session implementation class
 * @Date: Create in 14:43 2020/11/12
 */
public class DefaultSqlSession implements SqlSession{

    private Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementId, Object... params) throws Exception {

        //1. Build SQL executor
        SimpleExecutor simpleExecutor = new SimpleExecutor();

        //2. Get the final execution SQL object
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);

        //3. Execute SQL and return the result set
        List<Object> queryResultList = simpleExecutor.query(configuration, mappedStatement, params);
        return (List<E>)queryResultList;
    }

    @Override
    public <T> T selectOne(String statementId, Object... params) throws Exception {
        List<Object> objects = selectList(statementId, params);
        if (null != objects && objects.size() == 1){
            return (T)objects.get(0);
        } else {
           Throw new runtimeException ("the query result is empty or more than one result is returned");
        }
    }

    @Override
    public int update(String statementId, Object... params) {
        return 0;
    }

    @Override
    public int delete(String statementId, Object... params) {
        return 0;
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {

        //JDK dynamic proxy is used to generate proxy object for Dao interface and return call result
        Object proxyInstance =  Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler(){
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                //The bottom layer is still to execute JDBC
                //Depending on the situation, call selectlist or selectone
                //1. Prepare the parameter statementid = unique identifier of SQL statement: namespace.id  =Interface fully qualified name. Method name
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                String statementId = className + "." + methodName;

                //2. Prepare params (args)
                //Gets the return value type of the called method
                Type genericReturnType = method.getGenericReturnType();
                //Determine whether generic type parameterization is performed
                if ( genericReturnType instanceof ParameterizedType){
                    List<Object> objects = selectList(statementId, args);
                    return objects;
                }

                return selectOne(statementId,args);
            }
        });
        return (T)proxyInstance;

    }
}

Defaultsqlsessionfactory under sqlsession package

package com.panshenlian.sqlSession;

import com.panshenlian.pojo.Configuration;

/**
 * @Author: panshenlian
 *@ Description: default sqlsession factory implementation class
 * @Date: Create in 14:41 2020/11/12
 */
public class DefaultSqlSessionFactory implements  SqlSessionFactory{

    private Configuration configuration;

    public DefaultSqlSessionFactory(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public SqlSession openSession() {
        return new DefaultSqlSession(configuration);
    }
}

Executor under sqlsession package

package com.panshenlian.sqlSession;

import com.panshenlian.pojo.Configuration;
import com.panshenlian.pojo.MappedStatement;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.List;

/**
 * @Author: panshenlian
 *@ Description: SQL executor interface
 * @Date: Create in 15:02 2020/11/12
 */
public interface Executor {

    public <E> List<E> query(Configuration configuration,
                             MappedStatement mappedStatement,
                             Object... params) throws Exception;

}

Simple executor under sqlsession package

package com.panshenlian.sqlSession;

import com.mysql.jdbc.StringUtils;
import com.panshenlian.config.BoundSql;
import com.panshenlian.pojo.Configuration;
import com.panshenlian.pojo.MappedStatement;
import com.panshenlian.utils.GenericTokenParser;
import com.panshenlian.utils.ParameterMapping;
import com.panshenlian.utils.ParameterMappingTokenHandler;

import java.beans.ExceptionListener;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: panshenlian
 *@ Description: simple implementation class of SQL executor interface
 * @Date: Create in 15:55 2020/11/12
 */
public class SimpleExecutor implements Executor {

    @Override
    public <E> List<E> query(Configuration configuration,
                             MappedStatement mappedStatement,
                             Object... params) throws Exception {

        //1. Register the driver and get the database connection
        Connection connection = configuration.getDataSource().getConnection();

        //2. Get the SQL statement: select * from user where id = # {ID}
        //Convert SQL statement: select * from user where id =?
        //In the process of transformation, the values in # {} need to be parsed and stored
        String sql = mappedStatement.getSql();
        BoundSql bounSql = getBoundSql(sql);

        //3. Get the preprocessed object: Preparedstatement
        PreparedStatement preparedStatement =
                connection.prepareStatement(bounSql.getSqlText());

        //4. Set parameters and get parameters through reflection mechanism
        String parameterType = mappedStatement.getParameterType();
        Class<?> parameterTypeClass = getClassType(parameterType);

        List<ParameterMapping> parameterMappingList =
                bounSql.getParameterMappingList();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String filedName = parameterMapping.getContent();

            //Reflection
            Field declaredField = parameterTypeClass.getDeclaredField(filedName);
            //Violent visit
            declaredField.setAccessible(true);
            Object declaredFieldValue =  declaredField.get (params [0]); // params [0] is the object
            preparedStatement.setObject(i+1,declaredFieldValue);
        }

        //5. Execute SQL
        ResultSet resultSet = preparedStatement.executeQuery();
        String resultType = mappedStatement.getResultType();
        Class<?> resultTypeClass = getClassType(resultType);
        List<Object> objects = new ArrayList<Object>();

        //6. Encapsulate the returned result set
        while (resultSet.next()){
            Object o = resultTypeClass.newInstance();
            //Metadata
            ResultSetMetaData metaData = resultSet.getMetaData();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                //Field name
                String columnName = metaData.getColumnName(i);
                //Field value
                Object columnValue = resultSet.getObject(columnName);

                //Using introspection (reflection), according to the corresponding relationship between database tables and entities, the encapsulation is completed
                PropertyDescriptor propertyDescriptor =
                        new PropertyDescriptor(columnName, resultTypeClass);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o,columnValue);
            }
            objects.add(o);
        }
        return (List<E>)objects;
    }

    /**
     *Get the class according to the total path reflection of the parameter
     * @param parameterType
     * @return
     */
    private Class<?> getClassType(String parameterType) throws ClassNotFoundException {
        if (StringUtils.isNullOrEmpty(parameterType)) {
            return null;
        }
        Class<?> clazz = Class.forName(parameterType);
        return clazz;
    }

    /**
     *Complete the analysis of # {}: 1? Instead, 2. Resolve the value in # {} and store it
     * @param sql
     * @return
     */
    private BoundSql getBoundSql(String sql) {

        //Tag processing class, configure tag parser to complete the parsing of the placeholder
        ParameterMappingTokenHandler parameterMappingTokenHandler
                = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser =
                new GenericTokenParser("#{","}",
                        parameterMappingTokenHandler);

        //Parsed SQL
        String parseSql = genericTokenParser.parse(sql);
        //Resolved parameter name
        List<ParameterMapping> parameterMappings =
                parameterMappingTokenHandler.getParameterMappings();

        //Encapsulate the returned result of general configuration SQL
        BoundSql boundSql = new BoundSql(parseSql, parameterMappings);
        return boundSql;
    }
}

Sqlsession under sqlsession package

package com.panshenlian.sqlSession;

import java.util.List;

/**
 * @Author: panshenlian
 *@ Description: SQL session interface
 * @Date: Create in 14:40 2020/11/12
 */
public interface SqlSession {

    /**
     *Query all
     * @param statementId
     * @param params
     * @param <E>
     * @return
     */
    public <E> List<E> selectList(String statementId , Object ... params) throws Exception;

    /**
     *Query a single item according to the condition
     * @param statementId
     * @param params
     * @param <T>
     * @return
     */
    public <T> T selectOne(String statementId , Object ... params) throws Exception;

    /**
     *Update according to conditions
     * @param statementId
     * @param params
     * @return
     */
    public int update(String statementId , Object ... params);

    /**
     *Delete according to conditions
     * @param statementId
     * @param params
     * @return
     */
    public int delete(String statementId , Object ... params);

    /**
     *Generate proxy implementation class for Dao interface
     * @param mapperClass
     * @param <T>
     * @return
     */
    public <T> T getMapper(Class<?> mapperClass);

}

Sqlsessionfactory under sqlsession package

package com.panshenlian.sqlSession;

/**
 * @Author: panshenlian
 *@ Description: sqlsession factory interface
 * @Date: Create in 13:51 2020/11/12
 */
public interface SqlSessionFactory {

    public SqlSession openSession();
}

Sqlsessionfactorybuilder under sqlsession package

package com.panshenlian.sqlSession;

import com.panshenlian.config.XMLConfigBuilder;
import com.panshenlian.pojo.Configuration;

import java.io.InputStream;

/**
 * @Author: panshenlian
 *@ Description: sqlsession session session factory build class
 * @Date: Create in 13:48 2020/11/12
 */
public class SqlSessionFactoryBuilder {

    public SqlSessionFactory build(InputStream inputStream) throws Exception {

        //Step 1: use Dom4j to parse the configuration file and encapsulate the parsed content into configuration
        XMLConfigBuilder xmlConfigBuilder = new XMLConfigBuilder();
        Configuration configuration = xmlConfigBuilder.parseConfig(inputStream);

        //Step 2: create the sqlsessionfactory object and produce the sqlsession session object (factory mode)
        DefaultSqlSessionFactory defaultSqlSessionFactory =
                new DefaultSqlSessionFactory(configuration);

        return defaultSqlSessionFactory;
    }
}

Generictokenparser under utils package

/**
 *    Copyright 2009-2017 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.panshenlian.utils;

/**
 *General mark parser, mark # {and} to start and end processing
 * @author Clinton Begin
 */
public class GenericTokenParser {

  Private final string opentoken; // start tag
  Private final string closetoken; // end tag
  Private final tokenhandler; // tag processor

  public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
    this.openToken = openToken;
    this.closeToken = closeToken;
    this.handler = handler;
  }

  /**
   *Analysis of ${} and {}
   * @param text
   * @return
   *This method mainly implements the parsing and processing of the placeholder in the configuration file, script and other fragments, and returns the final required data.
   *Among them, the parsing work is completed by this method, and the processing work is implemented by the handletoken () method of the processor handler
   */
  public String parse(String text) {
    //Verify the parameter problem, if it is null, return an empty string.
    if (text == null || text.isEmpty()) {
      return "";
    }

    //Next, continue to verify whether the start tag is included. If it is not included, it is not a placeholder by default. Just return it as it is. Otherwise, continue to execute.
    int start = text.indexOf(openToken, 0);
    if (start == -1) {
      return text;
    }

   //Convert text to character array SRC, define the default offset offset = 0, and store the variable builder that needs to return the string,
    //The variable name expression corresponding to the place holder in the text variable. Judge whether start is greater than - 1 (that is, whether opentoken exists in text). If it exists, execute the following code
    char[] src = text.toCharArray();
    int offset = 0;
    final StringBuilder builder = new StringBuilder();
    StringBuilder expression = null;
    while (start > -1) {
     //If there is an escape character before marking, it will not be processed as an opentoken, otherwise it will continue to be processed
      if (start > 0 && src[start - 1] == '\') {
        builder.append(src, offset, start - offset - 1).append(openToken);
        offset = start + openToken.length();
      } else {
        //Reset the expression variable to avoid the interference of null pointer or old data.
        if (expression == null) {
          expression = new StringBuilder();
        } else {
          expression.setLength(0);
        }
        builder.append(src, offset, start - offset);
        offset = start + openToken.length();
        int end = text.indexOf(closeToken, offset);
        When (end > - 1) {// // when there is an end tag
          If (end > offset & & SRC [end - 1] = = '\ \') {// if there is an escape character in front of the end tag
            // this close token is escaped. remove the backslash and continue.
            expression.append(src, offset, end - offset - 1).append(closeToken);
            offset = end + closeToken.length();
            end = text.indexOf(closeToken, offset);
          }Else {// there is no escape character, that is, it needs to be processed as a parameter
            expression.append(src, offset, end - offset);
            offset = end + closeToken.length();
            break;
          }
        }
        if (end == -1) {
          // close token was not found.
          builder.append(src, start, src.length - start);
          offset = src.length;
        } else {
          //First, the parameter is processed according to the key (expression) of the parameter, and? Is returned as a placeholder
          builder.append(handler.handleToken(expression.toString()));
          offset = end + closeToken.length();
        }
      }
      start = text.indexOf(openToken, offset);
    }
    if (offset < src.length) {
      builder.append(src, offset, src.length - offset);
    }
    return builder.toString();
  }
}

Parametermapping in utils package

package com.panshenlian.utils;

/**
 * @Author: panshenlian
 *@ Description: parameter mapping class (SQL parameter mapping class, storing parameter names in # {}, ${})
 * @Date: Create in 16:14 2020/11/12
 */
public class ParameterMapping {

    private String content;

    public ParameterMapping(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

Parametermappingtokenhandler under utils package

package com.panshenlian.utils;

import java.util.ArrayList;
import java.util.List;

/**
 *Mark the processor implementation class, and parse # {}, ${} into?
 */
public class ParameterMappingTokenHandler implements TokenHandler {
    private List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();

    //Context is the parameter name # {ID} # {username}

    public String handleToken(String content) {
        parameterMappings.add(buildParameterMapping(content));
        return "?";
    }

    private ParameterMapping buildParameterMapping(String content) {
        ParameterMapping parameterMapping = new ParameterMapping(content);
        return parameterMapping;
    }

    public List<ParameterMapping> getParameterMappings() {
        return parameterMappings;
    }

    public void setParameterMappings(List<ParameterMapping> parameterMappings) {
        this.parameterMappings = parameterMappings;
    }

}

Tokenhandler under utils package

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.panshenlian.utils;

/**
 *Mark processor interface
 * @author Clinton Begin
 */
public interface TokenHandler {
  String handleToken(String content);
}

After the framework is written, let’s write a test project to verify the framework. We add a new test project (created in the form of module module) under the existing framework to ensure that the test project and the framework project are under the same working group

Complete solution of mybatis series (1): a persistence layer framework

Since I have written the test project, I can directly import it, and the effect is the same. I can create and import it in module mode

Complete solution of mybatis series (1): a persistence layer framework

Complete solution of mybatis series (1): a persistence layer framework

Complete solution of mybatis series (1): a persistence layer framework

Complete solution of mybatis series (1): a persistence layer framework

Complete solution of mybatis series (1): a persistence layer framework

Complete solution of mybatis series (1): a persistence layer framework

The basic process of test engineering is also described as follows:

1. Introduce dependency pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.panshenlian</groupId>
    <artifactId>MyPersistenceTest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <! -- introduce dependency of custom persistence layer framework -- >
    <dependencies>
        <dependency>
            <groupId>com.panshenlian</groupId>
            <artifactId>MyPersistence</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

2. Configure data sources sqlMapConfig.xml

<configuration>

    <! -- database configuration information -- >
    <dataSource>
        <property name="driverClass"
                  value="com.mysql.jdbc.Driver" ></property>
        <property name="jdbcUrl"
                  value="jdbc:mysql:///mybatis" ></property>
        <property name="userName"
                  value="root" ></property>
        <property name="password"
                  value="123456" ></property>
    </dataSource>

    <! -- applied to mapper.xml Full path -- >
    <mapper resource="userMapper.xml"></mapper>
    <mapper resource="orderMapper.xml"></mapper>

</configuration>

3. We take the user table as an example to establish the user SQL configuration userMapper.xml

<mapper namespace="com.panshenlian.dao.IUserDao">

    <! -- unique identity of SQL: namespace.id  To form: statementid -- >
    <select id="findAll"
            resultType="com.panshenlian.pojo.User">
        select * from user
    </select>

    <!--
        User user = new User();
        user.setId(1);
        user.setUsername("panshenlian");
    -->
    <select id="findByCondition"
            resultType="com.panshenlian.pojo.User"
            parameterType="com.panshenlian.pojo.User">
        select * from user
        where id= #{id} and username = #{username}
        and password= #{password} and birthday = #{birthday}
    </select>


</mapper>

4. User Dao interface

package com.panshenlian.dao;

import com.panshenlian.pojo.User;

import java.util.List;

/**
 * @Author: panshenlian
 * @Description:
 * @Date: Create in 21:35 2020/11/12
 */
public interface IUserDao {

    /**
     *Query all users
     * @return
     * @throws Exception
     */
    public List<User> findAll() throws Exception;

    /**
     *User query based on conditions
     * @return
     * @throws Exception
     */
    public User findByCondition(User user) throws Exception;

}

5. Entity class of user Dao

package com.panshenlian.pojo;

/**
 * @Author: panshenlian
 *@ Description: user entity
 * @Date: Create in 9:20 2020/11/12
 */
public class User {

    private Integer id;
    private String username;
    private String password;
    private String birthday;

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthday='" + birthday + '\'' +
                '}';
    }
}

Note: user SQL configuration file userMapper.xml This is the default rule of our framework: namespace=“ com.panshenlian.dao . iuserdao “at the same time, the ID of the select tag is consistent with the method name of the user Dao interface, which is also the default rule of the framework, such as id =” findall ““

6. Finally, we create a test class: mypersistencetest

package com.panshenlian.test;

import com.panshenlian.dao.IUserDao;
import com.panshenlian.io.Resource;
import com.panshenlian.pojo.User;
import com.panshenlian.sqlSession.SqlSession;
import com.panshenlian.sqlSession.SqlSessionFactory;
import com.panshenlian.sqlSession.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

/**
 * @Author: panshenlian
 *@ Description: persistence layer framework test class
 * @Date: Create in 9:24 2020/11/12
 */
public class MyPersistenceTest {

    @Test
    public void test() throws Exception {
        InputStream resourceAsStream =
                Resource.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory =
                new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //1、 Traditional Dao mode call
        User user = new User();
        user.setId(3);
        user.setUsername("panshenlian");
        user.setBirthday("2020-11-12");
        user.setPassword("123456");
        User dbUser = sqlSession.selectOne("com.panshenlian.dao.IUserDao.findByCondition",user);
        System.out.println(dbUser);
        List<User> userList = sqlSession.selectList("com.panshenlian.dao.IUserDao.findAll", user);
        for (User db : userList) {
            System.out.println(db);
        }

        //2、 Proxy mode call
        IUserDao userDao = sqlSession.getMapper(IUserDao.class);
        List<User> users = userDao.findAll();
        for (User db : users) {
            System.out.println (proxy call = + dB);
        }

    }
}

7. Running the test class, the results meet the expectations

Complete solution of mybatis series (1): a persistence layer framework

We have basically completed the framework and test verification. In fact, the above is mainly a brief introduction to the persistence layer framework. In the future, we will learn to analyze the mybatis framework. Basically, we have achieved a simulation prototype, and the process is roughly like this.

There are several interesting knowledge points involved in the process of coding implementation. We will talk about them later, including:

  • Introspection mechanism
  • Reflex mechanism
  • JDK dynamic proxy
  • Design pattern
  • generic paradigm

summary

Nowadays, large-scale projects generally do not directly use JDBC, either adopt the mature persistence layer scheme on the market, or develop the persistence layer framework by themselves. In the final analysis, pure JDBC can not guarantee efficient and stable data layer access and application. More and more persistence layer framework schemes not only eliminate a large number of JDBC redundant code, but also provide a very low learning curve, which can not only guarantee the data layer access and application Simultaneous interpreting of traditional databases also allows SQL statements, and provides extended integration support for other frameworks, including pool, cache, performance and so on.

At the beginning of its birth in the 1990s, JDBC was also brilliant and great. However, with the leap of technology level and the iterative updating of business scenarios, the old technology can not meet the existing demands. Everything will be updated in turn. We just stand on the shoulders of great people and change with the trend.

OK, the end of this article. Next, we may have a chatMybatis infrastructure and architecture

/ End.

Complete solution of mybatis series (1): a persistence layer framework

BIU ~Articles are continuously updated, wechat search “Pan and his friends“The first time to read, there are always surprises. This article will be published in GitHub https://github.com/JavaWorld Included, hot technology, framework, face-to-face, solutions, we will be the first time to deliver the most beautiful posture, welcome star.

Recommended Today

Practical react scaffold, simple react scaffold

Practical react scaffolding, no redundant documents, User defined react scaffold based on webpack, Project structure modularization, componentization, SSR, react server rendering, React + webpack + router + Redux + SSR JS / CSS extraction and compression Multi process packaging, routing, lazy loading, etc Multi page portal configuration, etc The source code address is as follows: […]