Getting started with MyBatis to customize the MyBatis framework

First MyBatis program (XML configuration)

In the previous article, I briefly summarized some limitations of native JDBC, and introduced the MyBatis framework. I sorted out how to build the working environment of MyBatis in detail

In this article, we start our first routine on the basis of setting up a good working environment. However, after we simply let the program run, we will explain how to customize the MyBatis framework. What is the meaning of it?

Although the first routine is relatively simple, there are many points that are easy to cause doubts. For example, why there are builder objects after using the factory mode? Through the custom framework, you can make your understanding of MyBatis deeper and better apply the framework

First of all, we want our first program to run

1. Set up the environment, and specify the location of the mapping configuration file in the main configuration file (SqlMapConfig.xml)

<! -- specify the location of the mapping profile -- >
<mappers>
    <mapper resource="cn/ideal/mapper/UserMapper.xml"/>
</mappers>

2. In the test folder, create a structure test class as shown in the figure

Because the method written in our mapper interface is a way to query all information, we can write it directly as shown in the figure below. This is the first routine. Later, we will talk about the points in detail, let our own program run and have a look

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

First MyBatis program (annotation configuration)

Annotation configuration. Naturally, our UserMapper.xml can be deleted. At the same time, 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();
}

Then in the main configuration file, use the class attribute to specify the annotated mapper fully qualified class name

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

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

Customize the MyBatis framework (use XML first)

First, we create a Maven project, modify its pom.xml file to add some necessary coordinates. Because we use dom4j to parse the XML file, 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-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>

Because today we are going to use the custom MyBatis framework to make a simple query, that is, to query all the User information in the table, we need to create corresponding User class entities 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 'User name',
  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;

Create the UserMapper interface and write related methods

package cn.ideal.mapper;

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

To set the main configuration file (SqlMapConfig.xml), it should be noted that since we need to simulate and design a MyBatis framework ourselves, we should not habitually add the corresponding DTD specification constraints. Here is the specific code

<?xml version="1.0" encoding="UTF-8"?>
<!-- mybatis Master profile -->
<configuration>
    <!-- Configuration environment, and spring After integration environments Configuration will be abolished -->
    <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>

    <!-- Specify the location of the mapping profile -->
    <mappers>
        <mapper resource="cn/ideal/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

Modify its SQL mapping profile

<?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>

Test classes, our test classes used today, are consistent with those used directly by MyBatis framework, but we need to implement some of them by 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 profile
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //Create SqlSessionFactory factory
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = factoryBuilder.build(in);
        //Using factories to produce SqlSession objects
        SqlSession session = factory.openSession();
        //Using SqlSession to create a proxy object for Mapper interface
        UserMapper userMapper = session.getMapper(UserMapper.class);
        //Using proxy objects to execute methods
        List<User> users = userMapper.findAllUserInfo();
        for (User user : users) {
            System.out.println(user);
        }
        //Release resources
        session.close();
        in.close();
    }
}

Let's refer to the real MyBatis. First, we need to regulate. Resources and SqlSessionFactoryBuilder classes need SqlSessionFactory and SqlSession For these two interfaces, then we need to create their corresponding implementation classes. For the rest, we need to create them again as needed. Then we need to add the corresponding methods to the created classes according to the needs of the test classes

###(1) Resources class

First, create a Resources class, and add a getResourceAsStream method in it. The parameter type is naturally a string type. According to the receiving type in the test class, it is determined that the return value type is InputStream, so you can write the specific method body, as shown in the following figure

package cn.ideal.mybatis.io;

import java.io.InputStream;

public class Resources {
    /**
     * Gets a byte input stream based on the parameters passed in
     * @param filePath
     * @return
     */
    public static InputStream getResourceAsStream(String filePath){
        // Obtain the bytecode of the current class, the classloader of the bytecode, and read the configuration according to the classloader
        return Resources.class.getClassLoader().getResourceAsStream(filePath);
    }
}

After getting the byte input stream of the main configuration file, we need to parse the XML. Here we use the XML parsing method of Dom4j. In Pom.xml, we have introduced its coordinates. We need to create its tool class. Of course, we can find a ready-made tool class, or write one manually. Our focus is on MyBatis On the implementation process of

(2) XMLConfigBuilder (parse the XML tool class and understand it)

Because of the way of XML configuration we first used, we don't care about the annotated part of XML for the moment, so we don't care about the annotated part for the moment

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 {
    /**
     * Parse the main configuration file and fill in the contents to the places required by the DefaultSqlSession
     * Technology used:
     *      dom4j+xpath,So you need to import the coordinates of dom4j and jaxen
     */
    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 SAXReader object
            SAXReader reader = new SAXReader();
            //2. Get the Document object according to the byte input stream
            Document document = reader.read(config);
            //3. Get root node
            Element root = document.getRootElement();
            //4. Use the method of selecting the specified node in xpath to obtain all property nodes
            List<Element> propertyElements = root.selectNodes("//property");
            //5. Traverse nodes
            for(Element propertyElement : propertyElements){
                //Determine which part of the information the node is connecting to the database
                //Get the value of the name attribute
                String name = propertyElement.attributeValue("name");
                if("driver".equals(name)){
                    //Presentation driver
                    //Get the value of the property tag value property
                    String driver = propertyElement.attributeValue("value");
                    cfg.setDriver(driver);
                }
                if("url".equals(name)){
                    //Represents a connection string
                    //Get the value of the property tag value property
                    String url = propertyElement.attributeValue("value");
                    cfg.setUrl(url);
                }
                if("username".equals(name)){
                    //Represents the user name
                    //Get the value of the property tag value property
                    String username = propertyElement.attributeValue("value");
                    cfg.setUsername(username);
                }
                if("password".equals(name)){
                    //Express password
                    //Get the value of the property tag value property
                    String password = propertyElement.attributeValue("value");
                    cfg.setPassword(password);
                }
            }
            //Take out all mapper tags in mappers, and judge whether they use resource or class attribute
            List<Element> mapperElements = root.selectNodes("//mappers/mapper");
            //Ergodic set
            for(Element mapperElement : mapperElements){
                //Determine which attribute mapperElement uses
                Attribute attribute = mapperElement.attribute("resource");
                if(attribute != null){
                    System.out.println("XML mode");
                    //Indicates that there is a resource attribute, which is XML
                    //Get the value of the property
                    String mapperPath = attribute.getValue();//Get the value of the attribute "com/itheima/dao/IUserDao.xml"
                    //Get the content of the map configuration file and encapsulate it into a map
                    Map<String, Mapper> mappers = loadMapperConfiguration(mapperPath);
                    //Assign values to mappers in configuration
                    cfg.setMappers(mappers);
                }else{
//                    System.out.println("annotation method");
//                    //Indicates that there is no resource attribute. Annotation is used
//                    //Get the value of the class property
//                    String daoClassPath = mapperElement.attributeValue("class");
//                    //Obtain the necessary information for encapsulation according to daoClassPath
//                    Map<String,Mapper> mappers = loadMapperAnnotation(daoClassPath);
//                    //Assign values to mappers in configuration
//                    cfg.setMappers(mappers);
                }
            }
            //Return to 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 passed in parameters and encapsulates it in the Map
     * @param mapperPath    Location of the mapping profile
     * @return  map It contains the unique ID obtained (key is composed of the fully qualified class name and method name of dao)
     *          And the necessary information for execution (value is a Mapper object, which stores the executed SQL statement 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 return value object
            Map<String,Mapper> mappers = new HashMap<String,Mapper>();
            //1. Get byte input stream according to path
            in = Resources.getResourceAsStream(mapperPath);
            //2. Get the Document object according to the byte input stream
            SAXReader reader = new SAXReader();
            Document document = reader.read(in);
            //3. Get root node
            Element root = document.getRootElement();
            //4. Get the value of the namespace attribute of the root node
            String namespace = root.attributeValue("namespace");//It is the key part of the map
            //5. Get all select nodes
            List<Element> selectElements = root.selectNodes("//select");
            //6. Traverse the select node set
            for(Element selectElement : selectElements){
                //Take the value of id attribute to form the key part of map
                String id = selectElement.attributeValue("id");
                //Take the value of the resultType property to form the value part of the map
                String resultType = selectElement.attributeValue("resultType");
                //Extract the text content to form the value part of the map
                String queryString = selectElement.getText();
                //Create Key
                String key = namespace+"."+id;
                //Create Value
                Mapper mapper = new Mapper();
                mapper.setQueryString(queryString);
                mapper.setResultType(resultType);
                //Store key and value in mappers
                mappers.put(key,mapper);
            }
            return mappers;
        }catch(Exception e){
            throw new RuntimeException(e);
        }finally{
            in.close();
        }
    }

    /**
     * According to the parameters passed in, we get all the methods annotated by the select annotation in dao.
     * According to the method name and class name, as well as the value of the annotated value attribute on the method, the necessary information of Mapper is formed
     * @param daoClassPath
     * @return
     */
//    private static Map<String,Mapper> loadMapperAnnotation(String daoClassPath)throws Exception{
//        //Define return value object
//        Map<String,Mapper> mappers = new HashMap<String, Mapper>();
//
//        //1. Get bytecode object of dao interface
//        Class daoClass = Class.forName(daoClassPath);
//        //2. Get the method array in dao interface
//        Method[] methods = daoClass.getMethods();
//        //3. Traverse Method array
//        for(Method method : methods){
//            //Take out each method and judge whether there is a select annotation
//            boolean isAnnotated = method.isAnnotationPresent(Select.class);
//            if(isAnnotated){
//                //Create Mapper object
//                Mapper mapper = new Mapper();
//                //Get the value attribute value of the annotation
//                Select selectAnno = method.getAnnotation(Select.class);
//                String queryString = selectAnno.value();
//                mapper.setQueryString(queryString);
//                //Gets the return value of the current method, which also requires generic information
//                Type type = method.getGenericReturnType();//List<User>
//                //Judge whether type is a parameterized type
//                if(type instanceof ParameterizedType){
//                    / / strong turn
//                    ParameterizedType ptype = (ParameterizedType)type;
//                    //Get the actual type parameters in the parameterized type
//                    Type[] types = ptype.getActualTypeArguments();
//                    //Take out the first one
//                    Class domainClass = (Class)types[0];
//                    //Get the class name of domainClass
//                    String resultType = domainClass.getName();
//                    //Assign value to Mapper
//                    mapper.setResultType(resultType);
//                }
//                //Assembly key information
//                //Get the name of the method
//                String methodName = method.getName();
//                String className = method.getDeclaringClass().getName();
//                String key = className+"."+methodName;
//                //Assign map
//                mappers.put(key,mapper);
//            }
//        }
//        return mappers;
//    }
}

Let's take a look at the code. First, get all the property nodes, get the values of drivers, user names, passwords, etc., and then

Take out all mapper tags in mappers, judge whether they use resource or class attribute, and then judge whether they use XML or annotation. For example, the XML method in this example will get the main configuration file < mapper resource = "cn/ideal/mapper/UserMapper.xml" / > in this sentence, cn/ideal/mapper/UserMapper.xml will be used to solve the SQL mapping configuration file Analysis, also extract some necessary information

However, if we want to use this tool class, we can see that there are still some errors reported. This is because we lack some necessary classes. We need to supplement them ourselves

First, we need to create a Configuration entity class to pass some link information we get

public class Configuration {
    
    private String driver;
    private String url;
    private String username;
    private String password;
    private Map<String, Mapper> mappers = new HashMap<String, Mapper>();
    
 	//Supplement its corresponding get set method   
    //Special note: setMappers need to use the append write method of putALL. It cannot be assigned directly. Otherwise, the old one will be overwritten by the new one
    public void setMappers(Map<String, Mapper> mappers) {
        this.mappers.putAll(mappers); // How to add
    }
}    

Secondly, we can see that when we parse the SQL mapping file, we encapsulate it into a Map collection, where the key is composed of the Mapper's fully qualified class name and method name. That is to say, we obtain the values of the two respectively, and then splice the strings into the key. The value is a Mapper object, its key is id, and the value is SQL statement and resultType

public class Mapper {

	private String queryString; //SQL
	private String resultType; / / fully qualified class name of entity class
	
	Supplement its corresponding get set method 
}

(3) SqlSessionFactoryBuilder class

We continue to return to the test class. We need to create a SqlSessionFactoryBuilder class. According to the test class, we pass the stream file obtained from the resource class as a parameter to the build method in this class. That is to say, in the build method, we need to parse the XML, and then use the Configuration class just created to receive it But according to the test class, we can know that the SqlSessionFactory type is used in the test to receive the build return. From the real MyBatis, we can see that SqlSessionFactory is an interface, and the builder design pattern is used here, so what we really want to return is its corresponding implementation class, and the Configuration object is passed in. The code is as follows: As shown below,

public class SqlSessionFactoryBuilder {
    public  SqlSessionFactory build(InputStream config){
        Configuration cfg = XMLConfigBuilder.loadConfiguration(config);
        return new DefaultSqlSessionFactory(cfg);
    }
}

(4) SqlSessionFactory interface

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

(5) DefaultSqlSessionFactor implementation class

Because we have passed Configuration into the method, so it is necessary to create a Configuration member first, then a structure with parameters, and also create its openSession method according to the test class to create objects for operating data. Here is the same idea. SqlSession is an interface, so we really need to return or its interface

public class DefaultSqlSessionFactory implements SqlSessionFactory {

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

    /**
     * Used to create a new operation database object
     * @return
     */
    public SqlSession openSession() {
        return new DefaultSqlSession(cfg);
    }
}

(6) SqlSession interface

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

public interface SqlSession {
    /**
     * Create a proxy object based on parameters
     * @param mapperInterfaceClass mapper Interface bytecode of
     * @param <T>
     * @return
     */
    <T> T getMapper(Class<T> mapperInterfaceClass);

    /**
     * Release resources
     */
    void close();
}

(7) DefaultSqlSession implementation class

First of all, we still need to create a member and a construction method with parameters. We need to create a tool class to create a data source named DataSourceUtil. At the same time, the more important thing in this class is to create our getMapper method. We use the method Proxy.newProxyInstance to create the parameters,

  • The first parameter is the classloader we need to proxy, that is, the classloader of the proxy
  • The second parameter is the interface that the dynamic proxy class needs to implement
  • When the third parameter dynamic proxy method is executed, it will call the method inside to execute (self created)
    • The parameter is to pass in the information in 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 proxy objects
     *
     * @param mapperInterfaceClass mapper Interface bytecode of
     * @param <T>
     * @return
     */
    public <T> T getMapper(Class<T> mapperInterfaceClass) {
        return (T) Proxy.newProxyInstance(mapperInterfaceClass.getClassLoader(),
                new Class[]{mapperInterfaceClass},new MapperProxy(cfg.getMappers(),connection));
    }

    /**
     * Used to release resources
     */
    public void close() {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

(8) DataSourceUtil tool class

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 new RuntimeException(e);
        }
    }
}

(9) MapperProxy

We started to implement the MapperProxy class we just customized, the regular creation members and constructors. The reason why we passed in Connection is that for the final execution of Executor(), another important thing of this class is to use invoke to enhance the methods, get and combine them,

public class MapperProxy implements InvocationHandler {

    //The key of map 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;
    }

    /**
     * Used to enhance methods. The enhancement here is to call the selectList method
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //Get method name
        String methodName = method.getName();
        //Get the name of the class where the method is located
        String className = method.getDeclaringClass().getName();
        //Combinatorial key
        String key = className + "." + methodName;
        //Get Mapper object in mappers
        Mapper mapper = mappers.get(key);
        //Judge whether there is mapper
        if (mapper == null){
            throw  new IllegalArgumentException("Wrong parameter passed in");
        }
        //Call tool class to query all 1
        return new Executor().selectList(mapper,connection);
    }
}

(10) Executor tool class

Then we use an off the shelf tool class to execute our SQL, because the SQL statement and resultType have been encapsulated in mapper and passed in

/**
 * Responsible for executing SQL statements and encapsulating the result set
 */
public class Executor {

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

                //Get meta information of result set: ResultSetMetaData
                ResultSetMetaData rsmd = rs.getMetaData();
                //Take out the total number of columns
                int columnCount = rsmd.getColumnCount();
                //Total number of traversal columns
                for (int i = 1; i <= columnCount; i++) {
                    //Get the name of each column. The sequence number of the column name starts from 1
                    String columnName = rsmd.getColumnName(i);
                    //Get the value of each column according to the column name
                    Object columnValue = rs.getObject(columnName);
                    //Assign value to obj: use Java introspection mechanism (implement property encapsulation with PropertyDescriptor)
                    PropertyDescriptor pd = new PropertyDescriptor(columnName,domainClass);//Requirement: the attribute of entity class and the column name of database table should be the same
                    //Get its write method
                    Method writeMethod = pd.getWriteMethod();
                    //Assign the value of the obtained column to the object
                    writeMethod.invoke(obj,columnValue);
                }
                //Adding a valued object to a 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();
            }
        }
    }
}

We can test it here. There is no problem with the result

How to define MyBatis by annotation

First, we need to change it to the form of annotation in the main configuration file, namely

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

Then create a custom Select annotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Select {
    /**
     * Configure the
     * @return
     */
    String value();
}

Then add annotation to our UserMapper interface method, and write the SQL statement in it

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

Finally, we will uncomment the part of XMLConfigBuilder tool class that has been commented out

The operation results are as follows:

Finally, I will give you the program structure chart, which is convenient for you to create a package. The structure is cn.ideal.xxxx

summary

I'll get back to it. The whole process

  • The configuration file related to MyBatis, SqlMapConfig.xml in the example is read by the method in the Rosource class to get a stream file
  • In SqlSessionFactoryBuilder, the Configuration file is parsed by XMLConfigBuilder. At the same time, the Configuration class is used to access and extract some specific Configuration information
  • Create a new operation database object through SqlSessionFactory
  • Get SqlSession
  • Using MapperProxy to execute SQL is essentially to call Executor executor
  • test run

Make a simple flow chart

Note: the code of this article comes from a certain horse. I reorganized and summarized it according to my thinking. Of course, it's not a copy. I also typed it once and simply explained and analyzed it. Naturally, there is no advanced technology to speak of. Maybe it can help some friends. Anyway, thanks for the support. If there are friends who need the original code, I will More links for your reference

Ending

If there are any shortcomings or mistakes in the article, please leave a message and share your ideas. Thank you for your support!

If you can help, then pay attention to me! If you prefer the way of reading WeChat articles, you can pay attention to my public number.

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

A public figure that persists in pushing original development technology articles: ideal two days

68 original articles published, 54 praised, 1401 visited
Private letter follow

Keywords: xml Mybatis Attribute Java

Added by Talguy on Sun, 02 Feb 2020 12:00:51 +0200