The first MyBatis program (XML Configuration)

In the last article, a brief summary of the limitations of native JDBC, at the same time led to the MyBatis framework, calculate a more detailed sort of how to build MyBatis working environment

This article, we in the beginning, now set up the work environment on the basis of our first routine, but, after simply let the program run, we will explain how to customize MyBatis framework, what is the meaning of it?

Although the first routine is relatively simple, many points in it are easy to cause confusion, and the whole execution process is not very clear. By customizing the framework, I can have a deeper understanding of MyBatis and better apply the framework

First, we want to get our first program up and running

1. Set up the environment and specify the location of the mapping configuration file in the master configuration file (SQLmapconfig.xml)

<! Mapping configuration file location -->
<mappers>
    <mapper resource="cn/ideal/mapper/UserMapper.xml"/>
</mappers>
Copy the code

2. In the Test folder, create a test class with the following structure

Since the method in our Mapper interface is a method to query all information, we can just write it as shown in the following figure. This is the first routine, and we will talk about it in detail later. Let your program run first

public class MyBatisTest {
    public static void main(String[] args) throws Exception {
        // Read the configuration file
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // Create the SqlSessionFactory
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = factoryBuilder.build(in);
        // Use factories to produce SqlSession objects
        SqlSession session = factory.openSession();
        // Create a proxy object for the Mapper interface using SqlSession
        UserMapper userMapper = session.getMapper(UserMapper.class);
        // Use proxy objects to execute methods
        List<User> users = userMapper.findAllUserInfo();
        for (User user : users) {
            System.out.println(user);
        }
        // Release resourcessession.close(); in.close(); }}Copy the code

The first MyBatis program (annotated configuration)

Annotation configuration, of course, we can remove the usermapper.xml, and we need to add annotations to the Mapper interface method as shown in the figure

public interface UserMapper {
    /** * Query all user information **@return* /
    @Select("select * from user")
    List<User> findAllUserInfo(a);
}
Copy the code

Then in the main configuration file, specify the annotated Mapper fully qualified class name using the class attribute

<mappers>
	<mapper class="cn.ideal.mapper.UserMapper"/>
</mappers>
Copy the code

The results of the two methods are the same, as shown in the following figure

Customize MyBatis framework (XML first)

First we create a Maven project and modify its POM.xml file to add the necessary coordinates. Since we parse the XML file using dom4j, we need to introduce Dom4j and Jaxen

<?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>cn.ideal</groupId>
    <artifactId>code_02_user_defined</artifactId>
    <version>1.0 the SNAPSHOT</version>
    
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</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>
Copy the code

Today we are going to use the custom MyBatis framework to conduct a simple query, that is, to query all User information in the table, so we need to create its User class entity according to the database content

CREATE DATABASE ideal_mybatis; Create database

CREATE TABLE USER (
  id		INT(11)NOT NULL AUTO_INCREMENT,
  username 	VARCHAR(32) NOT NULL COMMENT 'Username',
  telephone     VARCHAR(11) NOT NULL COMMENT 'mobile phone',
  birthday	DATETIME DEFAULT NULL COMMENT 'birthday',
  gender 	CHAR(1) DEFAULT NULL COMMENT 'gender',
  address	VARCHAR(256) DEFAULT NULL COMMENT 'address',
  PRIMARY KEY  (`id`))ENGINE=INNODB DEFAULT CHARSET=utf8;
Copy the code

Create the UserMapper interface and write the associated methods

package cn.ideal.mapper;

public interface UserMapper {
    /** * Query all user information */
    List<User> findAllUserInfo(a);
}
Copy the code

The main configuration file (SQLmapconfig.xml) needs to be explained: because we are to simulate the design of a MyBatis framework, so do not be used to add the corresponding DTD specification constraints, the following is the specific code

<?xml version="1.0" encoding="UTF-8"? >
<! -- Mybatis master configuration file -->
<configuration>
    <! -- Configuration environments will be scrapped after integration with Spring
    <environments default="development">
        <environment id="development">
            <! -- Use JDBC transaction management -->
            <transactionManager type="JDBC"></transactionManager>
            <! -- Database connection pool -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ideal_mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root99"/>
            </dataSource>
        </environment>
    </environments>

    <! Mapping configuration file location -->
    <mappers>
        <mapper resource="cn/ideal/mapper/UserMapper.xml"/>
    </mappers>
</configuration>
Copy the code

Modify its SQL mapping configuration file

<?xml version="1.0" encoding="UTF-8"? >
<mapper namespace="cn.ideal.mapper.UserMapper">
    <select id="findAllUserInfo" resultType="cn.ideal.domain.User">
        select * from user
    </select>
</mapper>
Copy the code

The test classes, the ones we use today, are the same as those used directly with the MyBatis framework, but we need to implement some of the classes and methods ourselves

package cn.ideal.test;

import cn.ideal.domain.User;
import cn.ideal.mapper.UserMapper;
import cn.ideal.mybatis.io.Resources;
import cn.ideal.mybatis.sqlsession.SqlSession;
import cn.ideal.mybatis.sqlsession.SqlSessionFactory;
import cn.ideal.mybatis.sqlsession.SqlSessionFactoryBuilder;

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

public class MyBatisTest {
    public static void main(String[] args) throws Exception {
        // Read the configuration file
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // Create the SqlSessionFactory
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = factoryBuilder.build(in);
        // Use factories to produce SqlSession objects
        SqlSession session = factory.openSession();
        // Create a proxy object for the Mapper interface using SqlSession
        UserMapper userMapper = session.getMapper(UserMapper.class);
        // Use proxy objects to execute methods
        List<User> users = userMapper.findAllUserInfo();
        for (User user : users) {
            System.out.println(user);
        }
        // Release resourcessession.close(); in.close(); }}Copy the code

The Resources and SqlSessionFactoryBuilder class require SqlSessionFactory and SqlSession. Then we also need to create the corresponding implementation class, the rest we need to create, and then according to the needs of the test class, for the created class to add the corresponding needs of the method

### #

Create a Resources class and add a getResourceAsStream method to the resource class. The parameter type is a string, and the return type is InputStream

package cn.ideal.mybatis.io;

import java.io.InputStream;

public class Resources {
    /** * gets a byte input stream * based on the argument passed in@param filePath
     * @return* /
    public static InputStream getResourceAsStream(String filePath){
        // Get the bytecode of the current class, get the bytecode classloader, read the configuration according to the classloader
        returnResources.class.getClassLoader().getResourceAsStream(filePath); }}Copy the code

After obtaining the byte input stream of the main configuration file, we need to parse the XML in it. Here we use Dom4j’s XML parsing method. We have introduced its coordinates in Pom. Our focus is still on the implementation process of MyBatis

XMLConfigBuilder (XMLConfigBuilder)

Because of the way we configured XML in the first place, we’ll leave the annotation part of XML behind for now, so we’ll leave the commented out part behind for now

package cn.ideal.mybatis.utils;

import cn.ideal.mybatis.cfg.Configuration;
import cn.ideal.mybatis.cfg.Mapper;
import cn.ideal.mybatis.io.Resources;
//import com.itheima.mybatis.annotations.Select;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/** * used to parse configuration files */
public class XMLConfigBuilder {
    /** * Parses the main configuration file and populates it where DefaultSqlSession needs it ** Uses the technique: * dom4j+xpath, so you need to import dom4j and JAXen coordinates */
    public static Configuration loadConfiguration(InputStream config){
        try{
            // Define the configuration object that encapsulates the connection information (mybatis configuration object)
            Configuration cfg = new Configuration();

            1. Get the SAXReader object
            SAXReader reader = new SAXReader();
            //2. Obtain the Document object from the byte input stream
            Document document = reader.read(config);
            3. Obtain the root node
            Element root = document.getRootElement();
            //4. Use xpath to select a node to obtain all property nodes
            List<Element> propertyElements = root.selectNodes("//property");
            //5. Traverse the node
            for(Element propertyElement : propertyElements){
                // Determine which part of the database the node is connected to
                // Fetch the value of the name attribute
                String name = propertyElement.attributeValue("name");
                if("driver".equals(name)){
                    // Indicates the driver
                    // Get the value of the property tag
                    String driver = propertyElement.attributeValue("value");
                    cfg.setDriver(driver);
                }
                if("url".equals(name)){
                    // represents a connection string
                    // Get the value of the property tag
                    String url = propertyElement.attributeValue("value");
                    cfg.setUrl(url);
                }
                if("username".equals(name)){
                    // Indicates the user name
                    // Get the value of the property tag
                    String username = propertyElement.attributeValue("value");
                    cfg.setUsername(username);
                }
                if("password".equals(name)){
                    // Indicates the password
                    // Get the value of the property tag
                    String password = propertyElement.attributeValue("value"); cfg.setPassword(password); }}// Take all mapper tags in mappers and determine whether they use the resource or class attribute
            List<Element> mapperElements = root.selectNodes("//mappers/mapper");
            // iterate over the collection
            for(Element mapperElement : mapperElements){
                // Determine which attribute mapperElement uses
                Attribute attribute = mapperElement.attribute("resource");
                if(attribute ! =null){
                    System.out.println("XML way");
                    // Indicates the resource attribute, using XML
                    // Fetch the value of the attribute
                    String mapperPath = attribute.getValue();/ / get the value of the attribute "com/itheima/dao/IUserDao. XML"
                    // Get the contents of the mapping configuration file and encapsulate it into a map
                    Map<String, Mapper> mappers = loadMapperConfiguration(mapperPath);
                    // Assign mappers in configuration
                    cfg.setMappers(mappers);
                }else{
// system.out.println (" annotation method ");
// // indicates that there is no resource attribute and that annotations are used
// // gets the value of the class attribute
// String daoClassPath = mapperElement.attributeValue("class");
// // obtain the necessary information for encapsulation according to daoClassPath
// Map
      
        mappers = loadMapperAnnotation(daoClassPath);
      ,mapper>
// // assign mappers in configuration
// cfg.setMappers(mappers);}}/ / returns the Configuration
            return cfg;
        }catch(Exception e){
            throw new RuntimeException(e);
        }finally{
            try {
                config.close();
            }catch(Exception e){ e.printStackTrace(); }}}/** * Parses the XML based on the parameters passed in and encapsulates it into a Map *@paramMapperPath Indicates the location of the mapping configuration file *@returnThe map contains the unique identity obtained (the key is made up of the DAO's fully qualified class name and method name) * and the necessary information for execution (the value is a Mapper object that holds the SQL statement being executed and the fully qualified class name of the entity class to be encapsulated) */
    private static Map<String,Mapper> loadMapperConfiguration(String mapperPath)throws IOException {
        InputStream in = null;
        try{
            // Define the return value object
            Map<String,Mapper> mappers = new HashMap<String,Mapper>();
            //1. Obtain the byte input stream based on the path
            in = Resources.getResourceAsStream(mapperPath);
            //2. Obtain the Document object from the byte input stream
            SAXReader reader = new SAXReader();
            Document document = reader.read(in);
            3. Obtain the root node
            Element root = document.getRootElement();
            //4. Obtain the namespace attribute value of the root node
            String namespace = root.attributeValue("namespace");// Is the component of the map key
            //5. Obtain all select nodes
            List<Element> selectElements = root.selectNodes("//select");
            //6. Iterate over the select node collection
            for(Element selectElement : selectElements){
                // Retrieve the value of the id attribute to form the key part of the map
                String id = selectElement.attributeValue("id");
                // Retrieves the values of the resultType attribute to form the value part of the map
                String resultType = selectElement.attributeValue("resultType");
                // Retrieve the text content that forms the value in the map
                String queryString = selectElement.getText();
                / / create a Key
                String key = namespace+"."+id;
                / / create the Value
                Mapper mapper = new Mapper();
                mapper.setQueryString(queryString);
                mapper.setResultType(resultType);
                // Put the key and value into mappers
                mappers.put(key,mapper);
            }
            return mappers;
        }catch(Exception e){
            throw new RuntimeException(e);
        }finally{ in.close(); }}/** * get all the methods in the DAO annotated by the SELECT annotation based on the arguments passed in. * The necessary information that makes up the Mapper based on the method name and class name and the value of the annotation value attribute on the method *@param daoClassPath
     * @return* /
// private static Map
      
        loadMapperAnnotation(String daoClassPath)throws Exception{
      ,mapper>
// // defines return value objects
// Map
      
        mappers = new HashMap
       
        ();
       ,>
      ,mapper>
//
// //1. Obtain the bytecode object of the DAO interface
// Class daoClass = Class.forName(daoClassPath);
// //2. Obtain an array of methods in the DAO interface
// Method[] methods = daoClass.getMethods();
// //3. Iterate through the Method array
// for(Method method : methods){
// // fetches each method to see if it has a SELECT annotation
// boolean isAnnotated = method.isAnnotationPresent(Select.class);
// if(isAnnotated){
// // Create a Mapper object
// Mapper mapper = new Mapper();
// // Retrieves the value of the annotation property
// Select selectAnno = method.getAnnotation(Select.class);
// String queryString = selectAnno.value();
// mapper.setQueryString(queryString);
// // gets the return value of the current method, also requiring generic information
// Type type = method.getGenericReturnType(); //List
      
// // Check whether type is a parameterized type
// if(type instanceof ParameterizedType){
/ / / / strong
// ParameterizedType ptype = (ParameterizedType)type;
// // gets the actual type parameters in the parameterized type
// Type[] types = ptype.getActualTypeArguments();
// // take out the first one
// Class domainClass = (Class)types[0];
// // Obtain the class name of domainClass
// String resultType = domainClass.getName();
// // Assign to Mapper
// mapper.setResultType(resultType);
/ /}
// // Assembly key information
// // Obtain the name of the method
// String methodName = method.getName();
// String className = method.getDeclaringClass().getName();
// String key = className+"."+methodName;
// // Assign a value to map
// mappers.put(key,mapper);
/ /}
/ /}
// return mappers;
/ /}
}

Copy the code

We can take a look at the code, first get all the property nodes, get the values of the driver, username, password, etc., and then

Take all the Mapper tags in Mappers and determine whether they are using the Resource or class attribute. This tells you whether you are using XML or annotations, as in this case, Just get to the main configuration file < mapper resource = “cn/ideal/mapper/UserMapper. XML” / > this sentence cn/ideal/mapper/UserMapper. XML and then to the SQL mapping configuration file parsing, Also extract some of the necessary information

But if we want to use this utility class, we can see that there are still some errors, and that’s because we’re missing some of the necessary classes, and we need to add them ourselves

First we need to create a Configuration entity class that passes in some of the link information that we get

public class Configuration {
    
    private String driver;
    private String url;
    private String username;
    private String password;
    private Map<String, Mapper> mappers = newHashMap<String, Mapper>(); Add its corresponding get set method// Special note: setMappers need to use putALL's append writing method. It is not possible to assign values directly, otherwise the old will be overwritten by the new
    public void setMappers(Map<String, Mapper> mappers) {
        this.mappers.putAll(mappers); // The append method}}Copy the code

Secondly, we can see that when parsing SQL mapping files, we encapsulate them into a Map set, in which key is composed of the fully qualified class name and method name of Mapper. That is, by obtaining the values of both respectively, and then concatenating the strings to form key, value is a Mapper object. The key is the ID, and the value is the SQL statement and resultType

public class Mapper {

	private String queryString; //SQL
	private String resultType; // The fully qualified class name of the entity classAdd its corresponding get set method}Copy the code

SqlSessionFactoryBuilder

Recourse Going back to the test class, we need to create a SqlSessionFactoryBuilder class. Based on the test class, we pass the stream files obtained in Recourse into the build method of this class as parameters. That is to say, in the build method, We need to parse the XML, and then use the Configuration class to receive the build, but from the test class, we can see that the SqlSessionFactory type is used to receive the build return. SqlSessionFactory is an interface that uses the Builder design pattern, so all we really need to do is return the corresponding implementation class and pass in the Configuration object, as shown below.

public class SqlSessionFactoryBuilder {
    public  SqlSessionFactory build(InputStream config){
        Configuration cfg = XMLConfigBuilder.loadConfiguration(config);
        return newDefaultSqlSessionFactory(cfg); }}Copy the code

(4) SqlSessionFactory interface

public interface SqlSessionFactory {
    /** * to open a new SqlSession object *@return* /
    SqlSession openSession(a);
}
Copy the code

(5) DefaultSqlSessionFactor implementation class

Since we are passing the Configuration into the method, it is necessary to create a Configuration member, then create a parameter construct, and also create its openSession method from the test class to create objects that manipulate the data. Same idea here, SqlSession is an interface, so what we really need to return is its interface

public class DefaultSqlSessionFactory implements SqlSessionFactory {

    private Configuration cfg;
    public DefaultSqlSessionFactory(Configuration cfg) {
        this.cfg = cfg;
    }

    /** * to create a new action database object *@return* /
    public SqlSession openSession(a) {
        return newDefaultSqlSession(cfg); }}Copy the code

SqlSession interface

Here we need to use SqlSession to create a proxy object for the Mapper interface

public interface SqlSession {
    /** * Creates a proxy object * based on the argument@paramMapperInterfaceClass Specifies the interface bytecode * of the mapper@param <T>
     * @return* /
    <T> T getMapper(Class<T> mapperInterfaceClass);

    /** * Release resources */
    void close(a);
}
Copy the code

DefaultSqlSession implementation class

We need to create a utility class to create a data source called DataSourceUtil, and the most important thing in this class is to create our getMapper method, which we use proxy.newProxyInstance. Where the parameters,

  • The first parameter is the class loader we need for the proxy, that is, whoever the proxy is, we will use the class loader
  • The second parameter is the interface that the dynamic proxy class needs to implement
  • The third argument is that when a dynamic proxy method is executed, it calls the method inside it to execute.
    • The argument is to pass in information from our configuration
public class DefaultSqlSession implements SqlSession {

    private Configuration cfg;
    private Connection connection;

    public DefaultSqlSession(Configuration cfg) {
        this.cfg = cfg;

        connection = DataSourceUtil.getConnection(cfg);
    }

    /** * used to create the proxy object **@paramMapperInterfaceClass Specifies the interface bytecode * of the mapper@param <T>
     * @return* /
    public <T> T getMapper(Class<T> mapperInterfaceClass) {
        return (T) Proxy.newProxyInstance(mapperInterfaceClass.getClassLoader(),
                new Class[]{mapperInterfaceClass},new MapperProxy(cfg.getMappers(),connection));
    }

    /** * To release resources */
    public void close(a) {
        if(connection ! =null) {
            try {
                connection.close();
            } catch(SQLException e) { e.printStackTrace(); }}}}Copy the code

DataSourceUtil tools

public class DataSourceUtil {
    public static Connection getConnection(Configuration cfg){
        try {
            Class.forName(cfg.getDriver());
            return DriverManager.getConnection(cfg.getUrl(),cfg.getUsername(),cfg.getPassword());
        } catch (Exception e) {
            throw newRuntimeException(e); }}}Copy the code

MapperProxy (9)

We started to implement a custom MapperProxy class, which normally creates members and constructors. The reason for passing Connection is that, in order to finally execute Executor(), the class also has an important invoke method enhancement. Take it and combine it,

public class MapperProxy implements InvocationHandler {

    // Map key is fully qualified class name + method name
    private Map<String, Mapper> mappers;
    private Connection connection;

    public MapperProxy(Map<String, Mapper> mappers,Connection connection) {
        this.mappers = mappers;
        this.connection = connection;
    }

    /** * is used to enhance the method by calling the selectList method *@param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // Get the method name
        String methodName = method.getName();
        // Get the name of the class of the method
        String className = method.getDeclaringClass().getName();
        //组合key
        String key = className + "." + methodName;
        // Get the Mapper object in mappers
        Mapper mapper = mappers.get(key);
        // Check whether mapper exists
        if (mapper == null) {throw  new IllegalArgumentException("Incorrect parameter passed in");
        }
        // Call the utility class to query all 1's
        return newExecutor().selectList(mapper,connection); }}Copy the code

Executor utility class

The next step is to use a ready-made utility class to execute our SQL, since the SQL statement, and resultType, are already wrapped in mapper and passed in

/** * is responsible for executing SQL statements and encapsulating result sets */
public class Executor {

    public <E> List<E> selectList(Mapper mapper, Connection conn) {
        PreparedStatement pstm = null;
        ResultSet rs = null;
        try {
            //1. Obtain data from mapper
            String queryString = mapper.getQueryString();//select * from user
            String resultType = mapper.getResultType();//com.itheima.domain.User
            Class domainClass = Class.forName(resultType);
            //2. Obtain the PreparedStatement object
            pstm = conn.prepareStatement(queryString);
            //3. Execute the SQL statement to obtain the result set
            rs = pstm.executeQuery();
            //4. Encapsulate the result set
            List<E> list = new ArrayList<E>();// Define the return value
            while(rs.next()) {
                // Instantiate the entity-class object to encapsulate
                E obj = (E)domainClass.newInstance();

                ResultSetMetaData: ResultSetMetaData
                ResultSetMetaData rsmd = rs.getMetaData();
                // Retrieve the total number of columns
                int columnCount = rsmd.getColumnCount();
                // Iterate over the total number of columns
                for (int i = 1; i <= columnCount; i++) {
                    // Get the name of each column, starting with 1
                    String columnName = rsmd.getColumnName(i);
                    // Obtain the value of each column based on the obtained column name
                    Object columnValue = rs.getObject(columnName);
                    // Assign to obj: Use Java introspection (encapsulate properties with PropertyDescriptor)
                    PropertyDescriptor pd = new PropertyDescriptor(columnName,domainClass);// The attributes of the entity class must be the same as the column names of the database table
                    // Get its write method
                    Method writeMethod = pd.getWriteMethod();
                    // Assign the column value to the object
                    writeMethod.invoke(obj,columnValue);
                }
                // Add the assigned object to the collection
                list.add(obj);
            }
            return list;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally{ release(pstm,rs); }}private void release(PreparedStatement pstm,ResultSet rs){
        if(rs ! =null) {try {
                rs.close();
            }catch(Exception e){ e.printStackTrace(); }}if(pstm ! =null) {try {
                pstm.close();
            }catch(Exception e){ e.printStackTrace(); }}}}Copy the code

At this point we can test it, and the result is no problem, right

How to customize MyBatis with annotations

First we need to modify the main configuration file to the form of annotations, i.e

<mappers>
	<mapper class="cn.ideal.mapper.UserMapper"/>
</mappers>
Copy the code

Then create a custom Select annotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Select {
    /** * Configures * for SQL statements@return* /
    String value(a);
}
Copy the code

Then add annotations to our UserMapper interface method to write the SQL statement in it

public interface UserMapper {
    /** * Query all user information **@return* /
    @Select("select * from user")
    List<User> findAllUserInfo(a);
}
Copy the code

Finally, uncomment the annotated portion of the XMLConfigBuilder utility class

The running results are as follows:

Finally, I give you the program structure diagram, so that you can create the package easily. The structure is CN.ide.xxxx

conclusion

Let me go over the process again

  • The configuration file associated with MyBatis, sqlmapconfig. XML in this example, is read by methods in the Rosource class, resulting in a stream file
  • In SqlSessionFactoryBuilder, the Configuration file is parsed by XMLConfigBuilder, and the Configuration class is used to access and extract some specific Configuration information
  • Create a new object to manipulate the database with SqlSessionFactory
  • Access to the SqlSession
  • The proxy mode MapperProxy is used to execute SQL, essentially calling the Executor Executor
  • A test run

Create a simple flow chart

Description: This article code from a horse, this article is according to the idea, I rearrange, summarizes the once, of course not copy, I knocked at the time, also real simple made a description and analysis, natural, no advanced technology may have some help to some friends, no matter how, or thank you support, if there is a need to the original code of friends, I am more a late links, For your reference

At the end

If there are any deficiencies or mistakes in the article, please leave a comment and share your thoughts. Thank you for your support!

If it helps you, follow me! If you prefer the way of reading articles on wechat, you can follow my official account

We don’t know each other here, but we are working hard for our dreams

A adhere to push original development of technical articles of the public number: ideal more than two days