MyBatis Learning Summary (4) - MyBatis Caching and Code Generation

Keywords: Java Mybatis Session MySQL

MyBatis Cache

Caching can improve system performance, speed up access, reduce server pressure and bring better user experience. Caching uses space for time, and a good cache has a high hit rate and a small amount of data. Caching is a very important technology.

1.0. Reencapsulate SqlSession FactoryUtils

In order to configure cache learning, we encapsulate the tool class again.

The original SqlSessionFactoryUtil tool class is as follows:

package com.zhangguo.mybatis03.utils;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * MyBatis Session Tool Class
 * */
public class SqlSessionFactoryUtil {

    /**
     * Get the Session Factory
     *
     * */
    public static SqlSessionFactory getFactory(){
        InputStream inputStream = null;
        SqlSessionFactory sqlSessionFactory=null;
        try{
            //Load conf.xml Configuration file, converted to input stream
            inputStream = SqlSessionFactoryUtil.class.getClassLoader().getResourceAsStream("mybatisCfg.xml");

            //Construct a configuration file based on the input stream SQL Conversational factory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
        finally {
            if(inputStream!=null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sqlSessionFactory;
    }

    /**
     * Get the sql session and submit it automatically
     * */
    public static SqlSession openSession(boolean isAutoCommit){
        return getFactory().openSession(isAutoCommit);
    }

    /**
     * Closing session
     * */
    public static void closeSession(SqlSession session){
        if(session!=null){
            session.close();
        }
    }

}

In the above code, we need to instantiate sqlSession Factory every time we get SQLSession, which is inefficient. Singleton improvements can be used:

package com.zhangguo.mybatis03.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * MyBatis Session Tool Class
 * */
public class SqlSessionFactoryUtils {

    /**Conversational factory*/
    private static SqlSessionFactory factory;

    static {
        try {
            /*Get the file stream of the configuration file*/
           InputStream inputStream=Resources.getResourceAsStream("mybatisCfg.xml");
           //Initialization Factory
            factory=new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Get the session object
     * Specifies whether to submit automatically
     * */
    public static SqlSession openSqlSession(boolean isAutoCommit){
        return getFactory().openSession(isAutoCommit);
    }

    public static SqlSessionFactory getFactory() {
        return factory;
    }
    public static void setFactory(SqlSessionFactory factory) {
        SqlSessionFactoryUtils.factory = factory;
    }

    /**
     * Closing session
     * */
    public static void closeSession(SqlSession session){
        if(session!=null){
            session.close();
        }
    }
}

1.1. MyBatis Cache Profile

In a system, the frequency of queries is much higher than that of additions, deletions and modifications. According to tripartite statistics, the proportion of different systems is between 9:1 and 7:3. Like most persistence tier frameworks, MyBatis also provides support for first-level caching and second-level caching

(1) The first level cache is a Perpetual Cache-based HashMap local cache with a storage scope of Session. When Session flush or close, all Caches in the Session will be emptied.

(2) The mechanism of the second level cache is the same as that of the first level cache. Perpetual Cache and HashMap are also used by default. The difference is that the storage scope is Mapper(Namespace), and the storage source can be customized, such as Ehcache.

(3) For the cache data update mechanism, when a C/U/D operation is performed in a scope (first-level cache Session/second-level cache Namespaces), the cache in all select s in that scope will be clear by default.

1.2. The default MyBatis level 1 cache is open

Test cases:

    /**Cache test*/
    @Test
    public void cacheTest(){
        //Open a session and do not submit automatically
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //Get a mapper
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //Query a single object by number
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);
        
        Student student2 = mapper1.selectStudentById(1);
        System.out.println(student2);
        //Close
        SqlSessionFactoryUtils.closeSession(session1);
    }

Result:

Although queried twice, only one SQL request was sent to the database, because the second time was the data obtained in the cache.

1.3, Level 1 cache is only valid in the same session (SQL Session)

Test cases:

    /**Cache test*/
    @Test
    public void cacheTest(){
        //Open a session 1 and do not submit automatically
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //Get a mapper
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //Query a single object by number
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);

        //Open a session 2, do not submit automatically
        SqlSession session2 = SqlSessionFactoryUtils.openSqlSession(false);
        //Get a mapper
        StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
        Student student2 = mapper2.selectStudentById(1);
        System.out.println(student2);
        //Close
        SqlSessionFactoryUtils.closeSession(session1);
    }

Result:

As can be seen from the figure above, the cache is not used at this time, and the database is queried twice, because the second query uses a new session, and the first level cache must be in the same session.

1.4. Clear the first level cache

(1) The cache will be emptied when the table is added or deleted

Test cases:

    /**Cache test*/
    @Test
    public void cacheTest(){
        //Open a session 1 and do not submit automatically
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //Get a mapper
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //Query a single object by number
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);

        //Execution update
        Student lili=new Student();
        lili.setId(5);
        lili.setSex("girl");
        mapper1.updateStudent(lili);

        Student student2 = mapper1.selectStudentById(1);
        System.out.println(student2);

        SqlSessionFactoryUtils.closeSession(session1);
    }

Result:

From the log, it can be seen that the second query also sent sql to the database, and the cache was not used because the update operation cache was emptied.

At this time, the data in the database is not really updated, as follows:

Since there is no manual submission, automatic submission can be set

/**Cache test*/
    @Test
    public void cacheTest(){
        //Open a session 1 and do not submit automatically
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //Get a mapper
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //Query a single object by number
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);

        //Execution update
        Student lili=new Student();
        lili.setId(5);
        lili.setSex("girl");
        mapper1.updateStudent(lili);

        Student student2 = mapper1.selectStudentById(1);
        System.out.println(student2);

        //Submission
        session1.commit();
        SqlSessionFactoryUtils.closeSession(session1);
    }

Submitted results

(2) Manual emptying

Test cases:

   /**Cache test*/
    @Test
    public void cacheTest(){
        //Open a session 1 and do not submit automatically
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //Get a mapper
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //Query a single object by number
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);

        //Perform manual updates
        session1.clearCache();

        Student student2 = mapper1.selectStudentById(1);
        System.out.println(student2);

        //Submission
        session1.commit();
        SqlSessionFactoryUtils.closeSession(session1);
    }

Result:

You can see from the log that the second query did not use the cache because the cache was emptied manually and the database was queried again if no cache was available.

Summary: After Session flush or close, all Cache s in the Session will be emptied; CUD will also be automatically emptied; manual emptying;

1.5. Open Level 2 Cache

The default secondary cache is not open and needs to be configured manually:

1.5.1, Global Switch

The default is true, and if it matches false, the rest of the Mapper XML files matching support cache is useless.

    <settings>
        <! - Set whether caching is allowed - >
        <setting name="cacheEnabled" value="true"/>
        <! - Setting the goal of log output - > 1.
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

1.5.2, single Mapper XML mapping file switch

The default Mapper XML mapping file does not use cache. Add one line to the configuration file to support cache:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhangguo.mybatis03.dao.StudentMapper">

    <cache/>
    
    <select id="selectStudentById" resultType="Student">
        SELECT id,name,sex from student where id=#{id}
    </select>
    
</mapper>

You can configure some properties manually when the secondary cache is turned on

<cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true"/>

The meanings of each attribute are as follows:

  • eviction: cache recovery strategy
    - LRU: Minimum Use Principle, removing objects that are not used for the longest time
    - FIFO: FIFO: First in, first out principle, recovery according to the order in which objects enter the cache
    - SOFT: Soft reference, removing objects based on garbage collector status and soft reference rules
    - WEAK: Weak reference, more active removal of objects based on garbage collector status and weak reference rules
  • Flush Interval: The refresh interval, in milliseconds, is configured here for 100 milliseconds. If not configured, the cache will be refreshed passively only when database modification is performed
  • size: Number of references representing the maximum number of objects that can be stored in the cache
  • readOnly: readOnly: readOnly: If true, all the same sql statements return the same object (which helps improve performance, but may not be safe when issuing and manipulating the same data). If set to false, the same sql is accessed, followed by a clone copy of cache.

1.5.3, Mapper State Switch

After the Mapper XML file configuration supports cache, all Mapper states in the file are supported. At this time, we should treat an article individually. We need to:

<select id="selectStudentById" resultType="Student" useCache="false">
    SELECT id,name,sex from student where id=#{id}
</select>

The access intention to the secondary cache can be set up under the specific method of Mapper:

  • useCache configuration

    If a statement needs the latest data every time, it means that it needs to query data from the database every time. You can set this property to false, for example:

<select id="selectAll" useCache="false">
  • Refresh the cache (that is, empty the cache)

    Secondary cache refreshes the cache by default after insert, update, delete operations. It can be configured manually without updating the cache, as follows:

<update id="updateById" flushCache="false" />

1.5.4. Implementing Serializable Interface

If a serializable interface is not implemented, an exception is thrown.

Modify POJO objects and add serializable interfaces:

package com.zhangguo.mybatis03.entities;

import java.io.Serializable;

/**
 * Student entity
 */
public class Student implements Serializable {
    private int id;
    private String name;
    private String sex;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

1.5.5 Notes

1. If readOnly is false, then the result set object is serializable.
<cache readOnly="false"/>
2. Before the SqlSession is closed, if the same condition is repeated, the local session cache is used instead of the cache mentioned above.
3. MyBatis caches the queried result set objects, not the result set data. It caches the mapped POJO object sets.
4. Faced with a certain amount of data, the built-in cache mode is useless.
5. The MyBatis framework is not good at caching query result sets. It should focus on sql mapper. It is more reasonable to use the Application of this framework to build caches, such as Redis, Ehcache, OSCache, Memcached, etc.

When our configuration file configures cacheEnabled=true, it opens the second level cache, which is mapper level. That is to say, different sqlsession uses the same mapper query, and the queried data may be the cache left by another sqlsession doing the same operation.

The order of query data is: secondary cache - > primary cache - > database.

1.6, Level 2 Cache Testing

By default, the first level cache is only valid in the same session:

Use case:

    /**Cache test*/
    @Test
    public void cacheTest(){
        //Open a session 1 and do not submit automatically
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //Get a mapper 1
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //Query a single object by number
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);
        
        //Open a session 2, do not submit automatically
        SqlSession session2 = SqlSessionFactoryUtils.openSqlSession(false);
        //Get a mapper 2
        StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
        //Query a single object by number
        Student student2 = mapper2.selectStudentById(1);
        System.out.println(student2);

        SqlSessionFactoryUtils.closeSession(session1);
        SqlSessionFactoryUtils.closeSession(session2);
    }

Result:

If you need to extend the scope to the same namespace, you can effectively use the secondary cache:

Use case:

    /**Cache test*/
    @Test
    public void cacheTest(){
        //Open a session 1 and do not submit automatically
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //Get a mapper 1
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //Query a single object by number
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);

        //Must submit manually, otherwise invalid
        session1.commit();

        //Open a session 2, do not submit automatically
        SqlSession session2 = SqlSessionFactoryUtils.openSqlSession(false);
        //Get a mapper 2
        StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
        //Query a single object by number
        Student student2 = mapper2.selectStudentById(1);
        System.out.println(student2);

        SqlSessionFactoryUtils.closeSession(session1);
        SqlSessionFactoryUtils.closeSession(session2);
    }

Result:

 

The query results will not be cached successfully if they are not submitted manually.

Using two different SqlSession objects to execute queries with the same query conditions, the second query will not send the SQL statement, but directly fetch the data from the cache.

Summary of Level 1.7 and Level 2 Caching

1. All select statements in the mapping statement file will be cached.

2. All insert, update and delete statements in the mapping statement file refresh the cache.

3. The cache is reclaimed using Least Current Used (LRU, the Least Recently Used) algorithm.

4. The cache is refreshed at specified intervals.

5. The cache stores 1024 objects

Common attributes of cache tags:

<cache 
eviction="FIFO"  <!--Recovery strategy is first in first out-->
flushInterval="60000" <!--Automatic refresh time 60 s-->
size="512" <!--Up to 512 reference objects are cached-->
readOnly="true"/> <!--read-only-->

2. MyBatis-Generator Code Generation

2.1. Create maven project in Intellij IDEA

A Maven project was created here, with no skeleton.

2.2. Adding dependencies

Add mybatis-generator-maven-plugin plug-in to pom.xml of Maven project

<?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.zhangguo.mybatis06</groupId>
    <artifactId>MyBatis06</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--MyBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!--MySql Database Driver -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <!-- JUnit Unit Testing Tool -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!-- mybatis-generator-core Reverse generation java Code-->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.5</version>
        </dependency>
    </dependencies>


    <!--mybatis Code Generation Plug-in-->
    <build>
        <finalName>MyBatis06</finalName>
        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.3. Configuration generation parameters

Create a configuration file named generatorConfig.xml in the src/main/resources directory under the Maven project as the execution target of the mybatis-generator-maven-plugin plug-in:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>

    <!--Import Property Configuration -->
    <properties resource="db.properties"></properties>

    <!--Designating a specific database jdbc drive jar Location of packages -->
    <classPathEntry location="${mysql.driverLocation}"/>

    <context id="default" targetRuntime="MyBatis3">

        <!-- optional,Aimed at creating class Controlling annotations -->
        <commentGenerator>
            <property name="suppressDate" value="true" />
        </commentGenerator>

        <!--jdbc Database Connection -->
        <jdbcConnection driverClass="${mysql.driver}" connectionURL="${mysql.url}" userId="${mysql.username}" password="${mysql.password}">
        </jdbcConnection>

        <!-- Non-essential, type processor, in database type and java Conversion control between types-->
        <javaTypeResolver >
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>

        <!-- Model Model Generator,Used to generate keys containing primary keys key Classes, Record Classes and Queries Example class
            targetPackage     Specify the generated model Generate the package name where it is located
            targetProject     Specify the path under the project
        -->
        <javaModelGenerator targetPackage="com.zhangguo.mybatis06.entities" targetProject="src/main/java">
            <!-- Is it right? model Adding constructors -->
            <property name="constructorBased" value="true"/>

            <!-- Whether subpackages are allowed, that is targetPackage.schemaName.tableName -->
            <property name="enableSubPackages" value="false"/>

            <!-- Established Model Whether the object can not be changed is generated Model Objects will not have setter Method, only construction method -->
            <property name="immutable" value="true"/>

            <!-- to Model Add a parent class -->
            <property name="rootClass" value="com.zhangguo.mybatis06.entities.BaseEntity"/>

            <!-- Are classes right? CHAR Data for columns of type trim operation -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!--Mapper The directory where the mapping file is generated generates the corresponding table for each database SqlMap file -->
        <sqlMapGenerator targetPackage="com.zhangguo.mybatis06.mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>


        <!-- Client code to generate easy-to-use targeted Model Object and XML Configuration file code
                type="ANNOTATEDMAPPER",generate Java Model And annotation-based Mapper object
                type="MIXEDMAPPER",Generating annotation-based Java Model And corresponding Mapper object
                type="XMLMAPPER",generate SQLMap XML Documentation and independence Mapper Interface
        -->
        <javaClientGenerator targetPackage="com.zhangguo.mybatis06.dao" targetProject="src/main/java" type="MIXEDMAPPER">
            <property name="enableSubPackages" value=""/>
            <!--
                    //Define the visibility of the ByExample() method in Maper.java source code with optional values:
                    public;
                    private;
                    protected;
                    default
                    //Note: If targetRuntime= "MyBatis 3", this parameter is ignored
             -->
            <property name="exampleMethodVisibility" value=""/>
            <!--
               //Method name counter
              Important note: this property is ignored if the target runtime is MyBatis3.
             -->
            <property name="methodNameCalculator" value=""/>

            <!--
              //Adding a parent interface to the generated interface
             -->
            <property name="rootInterface" value=""/>
        </javaClientGenerator>



        <table tableName="student" schema="nfmall"></table>
        <table tableName="category" schema="nfmall"></table>
        <table tableName="goods" schema="nfmall"></table>
    </context>
</generatorConfiguration>

The attribute resource file here shares the db.propities file with mybatis

##MySQL connection string
#drive
mysql.driver=com.mysql.jdbc.Driver
#address
mysql.url=jdbc:mysql://127.0.0.1:3306/nfmall?useUnicode=true&characterEncoding=UTF-8
#User name
mysql.username=root
#Password
mysql.password=uchr@123
#Driving position
mysql.driverLocation=E:\\NF\\Java\\JDBC\\mysql-connector-java-5.1.47\\mysql-connector-java-5.1.47.jar

Parametric Profile 1:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC
        "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>

    <!-- Local database driver jar Full Path of Packet -->
    <classPathEntry location=""/>

    <context id="context" targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressAllComments" value="false"/>
            <property name="suppressDate" value="true"/>
        </commentGenerator>

        <!-- Relevant configuration of database -->
        <jdbcConnection driverClass="" connectionURL="" userId="" password=""/>

        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <!-- Location of entity class generation -->
        <javaModelGenerator targetPackage="Target pack" targetProject="Target project classpath">
            <property name="enableSubPackages" value="false"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!-- *Mapper.xml Location of files -->
        <sqlMapGenerator targetPackage="Target pack" targetProject="Target project classpath">
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>

        <!-- Mapper Location of interface file -->
        <javaClientGenerator targetPackage="Target pack" targetProject="Target project classpath" type="XMLMAPPER">
            <property name="enableSubPackages" value="false"/>
        </javaClientGenerator>

        <!-- Configuration of related tables -->
        <table tableName="Table name" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
               enableUpdateByExample="false"/>
    </context>
</generatorConfiguration>

Reference Profile II:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE generatorConfiguration  
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"  
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">  
<generatorConfiguration>  
    <!--Import Property Configuration -->  
    <properties resource="generator.properties"></properties>  
  
    <!--Designating a specific database jdbc drive jar Location of packages -->  
    <classPathEntry location="${jdbc.driverLocation}"/>  
  
    <context id="default" targetRuntime="MyBatis3">  
  
  
        <!-- optional,Aimed at creating class Controlling annotations -->  
        <commentGenerator>  
            <property name="suppressDate" value="true" />  
        </commentGenerator>  
  
  
        <!--jdbc Database Connection -->  
        <jdbcConnection driverClass="${jdbc.driverClass}" connectionURL="${jdbc.connectionURL}" userId="${jdbc.userId}" password="${jdbc.password}">  
        </jdbcConnection>  
  
  
  
        <!-- Non-essential, type processor, in database type and java Conversion control between types-->  
        <javaTypeResolver >  
            <property name="forceBigDecimals" value="false" />  
        </javaTypeResolver>  
  
        <!-- Model Model Generator,Used to generate keys containing primary keys key Classes, Record Classes and Queries Example class  
            targetPackage     Specify the generated model Generate the package name where it is located  
            targetProject     Specify the path under the project  
        -->  
        <javaModelGenerator targetPackage="org.louis.hometutor.po" targetProject="src/main/java">  
            <!-- Is it right? model Adding constructors -->  
            <property name="constructorBased" value="true"/>  
  
            <!-- Whether subpackages are allowed, that is targetPackage.schemaName.tableName -->  
            <property name="enableSubPackages" value="false"/>  
  
            <!-- Established Model Whether the object can not be changed is generated Model Objects will not have setter Method, only construction method -->  
            <property name="immutable" value="true"/>  
  
            <!-- to Model Add a parent class -->  
            <property name="rootClass" value="com.foo.louis.Hello"/>  
  
            <!-- Are classes right? CHAR Data for columns of type trim operation -->  
            <property name="trimStrings" value="true"/>  
        </javaModelGenerator>  
  
        <!--Mapper The directory where the mapping file is generated generates the corresponding table for each database SqlMap file -->  
        <sqlMapGenerator targetPackage="org.louis.hometutor.domain" targetProject="src/main/java">  
            <property name="enableSubPackages" value="false"/>  
        </sqlMapGenerator>  
  
  
        <!-- Client code to generate easy-to-use targeted Model Object and XML Configuration file code  
                type="ANNOTATEDMAPPER",generate Java Model And annotation-based Mapper object  
                type="MIXEDMAPPER",Generating annotation-based Java Model And corresponding Mapper object  
                type="XMLMAPPER",generate SQLMap XML Documentation and independence Mapper Interface  
        -->  
        <javaClientGenerator targetPackage="com.foo.tourist.dao" targetProject="src/main/java" type="MIXEDMAPPER">  
            <property name="enableSubPackages" value=""/>  
            <!--  
                    //Define the visibility of the ByExample() method in Maper.java source code with optional values:  
                    public;  
                    private;  
                    protected;  
                    default  
                    //Note: If targetRuntime= "MyBatis 3", this parameter is ignored  
             -->  
            <property name="exampleMethodVisibility" value=""/>  
            <!--  
                                           //Method name counter  
              Important note: this property is ignored if the target runtime is MyBatis3.  
             -->  
            <property name="methodNameCalculator" value=""/>  
  
            <!-- 
                                                //Adding a parent interface to the generated interface 
             -->  
            <property name="rootInterface" value=""/>  
  
        </javaClientGenerator>  
  
  
  
        <table tableName="lession" schema="louis">  
  
            <!-- optional   , only for mybatis3 runtime  
                 //Automatically generated key values (identity, or sequence values)  
               //If this element is specified, the MBG generates the < selectKey > element, which is then inserted into the < Insert > element of the SQL Map.  
               sqlStatement The statement will return a new value  
               //If it is a self-increasing primary key, you can use predefined statements or add custom SQL statements. The predefined values are as follows:  
                  Cloudscape    This will translate to: VALUES IDENTITY_VAL_LOCAL()  
                  DB2:      VALUES IDENTITY_VAL_LOCAL()  
                  DB2_MF:       SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1  
                  Derby:        VALUES IDENTITY_VAL_LOCAL()  
                  HSQLDB:   CALL IDENTITY()  
                  Informix:     select dbinfo('sqlca.sqlerrd1') from systables where tabid=1  
                  MySql:        SELECT LAST_INSERT_ID()  
                  SqlServer:    SELECT SCOPE_IDENTITY()  
                  SYBASE:   SELECT @@IDENTITY  
                  JDBC:     This will configure MBG to generate code for MyBatis3 suport of JDBC standard generated keys. 
This is a database independent method of obtaining the value from identity columns.  
                  identity: Self increasing primary key  If true, then the column is flagged as an identity column and the generated <selectKey> 
element will be placed after the insert (for an identity column). If false, then the generated <selectKey> will be placed before
 the insert (typically for a sequence).  
  
            -->  
            <generatedKey column="" sqlStatement="" identity="" type=""/>  
  
  
            <!-- optional.  
                    //Column naming rules:  
                    MBG Use <columnRenamingRule> The element renames the column name before calculating the corresponding name of the column name.  
                    //Function: It is generally necessary to filter BUSI_before BUSI_CLIENT_NO  
                    //Supporting positive expressions  
                     searchString A string representing the string to be replaced  
                     replaceString It's a string to be replaced. By default, it's an empty string, optional.  
            -->  
            <columnRenamingRule searchString="" replaceString=""/>  
  
  
  
            <!-- optional.tell MBG Ignore a column  
                    column,Columns to be ignored  
                    delimitedColumnName:true ,matching column The value of the value matches the case of the name of the database column. false Ignore case matching  
                    //Whether to limit the column name of a table, that is, the name of a fixed table column in Model  
            -->  
            <ignoreColumn column="PLAN_ID"  delimitedColumnName="true" />  
  
  
            <!--optional.cover MBG Yes Model Generative Rules  
                 column: Column Name of Database  
                 javaType: Corresponding Java Fully qualified name of data type  
                 //When necessary, you can override the java data types computed by java TypeResolver. For some databases, this is necessary to handle "odd" 
database types (e.g. MySql's unsigned bigint type should be mapped to java.lang.Object).  
                 jdbcType:The column JDBC data type(INTEGER, DECIMAL, NUMERIC, VARCHAR, etc.),This column can be overridden by JavaTypeResolver Calculated Jdbc Type,
//For some databases, it is necessary to deal with specific JDBC driver preferences (e.g. DB2's LONGVARCHAR type should be mapped to VARCHAR for iBATIS).  
                 typeHandler:  
  
            -->  
            <columnOverride column="" javaType=""    jdbcType="" typeHandler=""  delimitedColumnName="" />  
  
        </table>  
    </context>  
</generatorConfiguration>  

Property resource file:

jdbc.driverLocation=E:\\NF\\Java\\JDBC\\mysql-connector-java-5.1.47\\mysql-connector-java-5.1.47.jar
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.connectionURL=jdbc:mysql://127.0.0.1:3306/nfmall?useUnicode=true&characterEncoding=UTF-8
jdbc.userId=root
jdbc.password=uchr@123

Using the external configuration file generator.properties, you can configure the following properties into the properties file to increase the flexibility of configuration:

The project catalogue is as follows:

2.4. Execution Generation

Find Plugins - > mybatis - Generator - > mybatis - generator in Maven Projects: generate

Click Run, and then, without any surprise, it will output in the console:

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building MyBatis06 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- mybatis-generator-maven-plugin:1.3.2:generate (default-cli) @ MyBatis06 ---
[INFO] Connecting to the Database
[INFO] Introspecting table nfmall.student
log4j:WARN No appenders could be found for logger (org.mybatis.generator.internal.db.DatabaseIntrospector).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
[INFO] Introspecting table nfmall.category
[INFO] Introspecting table nfmall.goods
[INFO] Generating Example class for table student
[INFO] Generating Record class for table student
[INFO] Generating Mapper Interface for table student
[INFO] Generating SQL Map for table student
[INFO] Generating Example class for table category
[INFO] Generating Record class for table category
[INFO] Generating Mapper Interface for table category
[INFO] Generating SQL Map for table category
[INFO] Generating Example class for table goods
[INFO] Generating Record class for table goods
[INFO] Generating Mapper Interface for table goods
[INFO] Generating SQL Map for table goods
[INFO] Saving file StudentMapper.xml
[INFO] Saving file CategoryMapper.xml
[INFO] Saving file GoodsMapper.xml
[INFO] Saving file StudentExample.java
[INFO] Saving file Student.java
[INFO] Saving file StudentMapper.java
[INFO] Saving file CategoryExample.java
[INFO] Saving file Category.java
[INFO] Saving file CategoryMapper.java
[INFO] Saving file GoodsExample.java
[INFO] Saving file Goods.java
[INFO] Saving file GoodsMapper.java
[WARNING] Root class com.zhangguo.mybatis06.entities.BaseEntity cannot be loaded, checking for member overrides is disabled for this class 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.845 s
[INFO] Finished at: 2018-10-10T09:51:45+08:00
[INFO] Final Memory: 11M/162M
[INFO] ------------------------------------------------------------------------

If you see BUILD SUCCESS, you will succeed. If there is a mistake, you will print out the detailed error information because of adding the - e option. You can modify it according to the error information.

Generate results:

2.5. Use generated code

1. MyBatis Session Tool Class

package com.zhangguo.mybatis06.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * MyBatis Session Tool Class
 * */
public class SqlSessionFactoryUtils {

    /**Conversational factory*/
    private static SqlSessionFactory factory;

    static {
        try {
            /*Get the file stream of the configuration file*/
           InputStream inputStream=Resources.getResourceAsStream("mybatisCfg.xml");
           //Initialization Factory
            factory=new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Get the session object
     * Specifies whether to submit automatically
     * */
    public static SqlSession openSqlSession(boolean isAutoCommit){
        return getFactory().openSession(isAutoCommit);
    }

    public static SqlSessionFactory getFactory() {
        return factory;
    }
    public static void setFactory(SqlSessionFactory factory) {
        SqlSessionFactoryUtils.factory = factory;
    }

    /**
     * Closing session
     * */
    public static void closeSession(SqlSession session){
        if(session!=null){
            session.close();
        }
    }
}

2. MyBatis Core Profile

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--Import db.properties All in the file key-value data-->
    <!--Externally introduced content will cover internally defined-->
    <properties resource="db.properties">
        <!--Define a name as driver,The value is com.mysql.jdbc.Driver Attribute-->
        <property name="mysql.driver" value="com.mysql.jdbc.Driver"></property>
    </properties>

    <settings>
        <!--Set whether caching is allowed-->
        <setting name="cacheEnabled" value="true"/>
        <!--Setting the target of log output-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--alias-->
    <typeAliases>
        <!--Define a single alias with the specified name student,The corresponding type is com.zhangguo.mybatis02.entities.Student-->
        <!--<typeAlias type="com.zhangguo.mybatis02.entities.Student" alias="student"></typeAlias>-->
        <!--Specifies that all classes under the package name are automatically scanned and default aliases are defined.
        mybatis Automatic scanning of packages pojo Class, automatically define aliases, aliases are class names(Both capitals and lowercases are acceptable.)-->
        <package name="com.zhangguo.mybatis03.entities"></package>
    </typeAliases>

    <!--Register a custom type processor-->
    <typeHandlers>
        <!--<typeHandler handler="" javaType="" jdbcType=""></typeHandler>-->
    </typeHandlers>

    <!--Environmental configuration, default Environment selected for default-->
    <environments default="development">
        <!--Development-->
        <environment id="development">
            <!--transaction management-->
            <transactionManager type="JDBC"/>
            <!--Connection pool-->
            <dataSource type="POOLED">
                <!--Reference attribute ${mysql.driver}-->
                <property name="driver" value="${mysql.driver}"/>
                <property name="url" value="${mysql.url}"/>
                <property name="username" value="${mysql.username}"/>
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>
        <!--Function-->
        <environment id="work">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/nfmall?useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="uchr@123"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--Register one based on the path XML Mapper-->
        <mapper resource="com/zhangguo/mybatis06/mapper/studentMapper.xml"/>

    </mappers>

</configuration>

3. Test cases

package test;

import com.zhangguo.mybatis06.dao.StudentMapper;
import com.zhangguo.mybatis06.entities.Student;
import com.zhangguo.mybatis06.entities.StudentExample;
import com.zhangguo.mybatis06.utils.SqlSessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class StudentTest {
    /***
     * List<Student> selectByExample(StudentExample example);
     */
    @Test
    public void testSelectByExample(){

        List<Student> entities = null;
        //Open a session
        SqlSession session = SqlSessionFactoryUtils.openSqlSession(true);

        //Get a mapper
        StudentMapper mapper = session.getMapper(StudentMapper.class);

        StudentExample studentExample=new StudentExample();
        //The query name contains a
        studentExample.createCriteria().andNameLike("%a%");

        //Query multiple objects, specify parameters
        entities = mapper.selectByExample(studentExample);
        //Close
        SqlSessionFactoryUtils.closeSession(session);

    }

}

Test results:

3. MyBatis-GUI Code Generator mybatis-generator-gui

3.1, outline

Source address: https://github.com/zouzg/mybatis-generator-gui

mybatis-generator-gui is based on mybatis generator Develop an interface tool that makes it very easy and fast to generate Mybatis Java POJO files and database Mapping files.

3.2. Core characteristics

  • It is easy to generate code according to the interface steps, eliminating the tedious process of learning and configuring XML.
  • Save the database connection and Generator configuration, and each code generation is easy to handle.
  • Built-in common plug-ins, such as paging plug-ins
  • Generate the annotations of the tables and columns in the database into the annotations of Java entities, and the generated entities are clear and clear.
  • Optionally remove comments that are not friendly to version management, so that new or deleted fields can be generated more clearly.
  • At present, Mysql, Mysql 8, Oracle, PostgreSQL and SQL Server have been supported, but no support for other non-mainstream databases is provided.

3.3, requirements

Because of the many features of Java 8, this tool requires JDK version 1.8.0.60 or more, and JDK version 1.9 is not yet supported.

3.4, Download

You can download this tool from this link: https://github.com/astarring/mybatis-generator-gui/releases

3.5. Start the software

  • Method 1: Self-help construction (note that the project name needs to be modified according to the case)
    git clone https://github.com/astarring/mybatis-generator-gui
    cd mybatis-generator-gui
    mvn jfx:jar
    cd target/jfx/app/
    java -jar mybatis-generator-gui.jar

 

  • Method 2: Running in IDE

Start in Eclipse or IntelliJ IDEA, find the com.zzg.mybatis.generator.MainUI class and run it.

  • Method 3: Pack it as a native application, double-click the shortcut to start, convenient and fast.

    If you don't want the packaged installation package logo to be a grey teacup for Java, you need to release the icon annotations corresponding to the operating system platform in the pom file.

    #<icon>${project.basedir}/package/windows/mybatis-generator-gui.ico</icon>by windows
    #<icon>${project.basedir}/package/macosx/mybatis-generator-gui.icns</icon>by mac
    mvn jfx:native

 

In addition, it should be noted that if windows system is packaged as exe, it needs to install WiX Toolset 3 + environment; because jre will be packaged into the installation package, both platforms are about 100M, larger size, please pack it yourself; the packaged installation package is in the target/jfx/native directory.

3.6. Notes

  • This automatic code generation tool is only suitable for adding, deleting and modifying single tables. For joint queries of databases, please write new XML and Mapper by yourself.
  • Some systems cannot input text in the input box when using Chinese input method. Please switch to English input method.
  • If you don't understand what the corresponding field or option means, place the cursor on the corresponding field or Label for a while and then explain if there is an explanation.

3.7, document

Refer to Wiki in this library for more detailed documentation.

3.8. Code generation example

3.8.1. Create a Maven project

3.8.2. Download the source code and open it using IDEA

Download address: https://github.com/zouzg/mybatis-generator-gui/releases

After decompression, it is introduced into IDEA

Find the MainUI class

3.8.3. Running procedures

3.8.4, Connecting to Data

 

3.8.5, Generating Code

3.8.6. Use generated code

POM:

<?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.zhangguo.mybatis05</groupId>
    <artifactId>MyBatis05</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--MyBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!--MySql Database Driver -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <!-- JUnit Unit Testing Tool -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Tools:

package com.zhangguo.mybatis05.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * MyBatis Session Tool Class
 * */
public class SqlSessionFactoryUtils {

    /**Conversational factory*/
    private static SqlSessionFactory factory;

    static {
        try {
            /*Get the file stream of the configuration file*/
           InputStream inputStream=Resources.getResourceAsStream("mybatisCfg.xml");
           //Initialization Factory
            factory=new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Get the session object
     * Specifies whether to submit automatically
     * */
    public static SqlSession openSqlSession(boolean isAutoCommit){
        return getFactory().openSession(isAutoCommit);
    }

    public static SqlSessionFactory getFactory() {
        return factory;
    }
    public static void setFactory(SqlSessionFactory factory) {
        SqlSessionFactoryUtils.factory = factory;
    }

    /**
     * Closing session
     * */
    public static void closeSession(SqlSession session){
        if(session!=null){
            session.close();
        }
    }
}

Core Profile:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--Import db.properties All in the file key-value data-->
    <!--Externally introduced content will cover internally defined-->
    <properties resource="db.properties">
        <!--Define a name as driver,The value is com.mysql.jdbc.Driver Attribute-->
        <property name="mysql.driver" value="com.mysql.jdbc.Driver"></property>
    </properties>

    <settings>
        <!--Set whether caching is allowed-->
        <setting name="cacheEnabled" value="true"/>
        <!--Setting the target of log output-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--alias-->
    <typeAliases>
        <!--Define a single alias with the specified name student,The corresponding type is com.zhangguo.mybatis02.entities.Student-->
        <!--<typeAlias type="com.zhangguo.mybatis02.entities.Student" alias="student"></typeAlias>-->
        <!--Specifies that all classes under the package name are automatically scanned and default aliases are defined.
        mybatis Automatic scanning of packages pojo Class, automatically define aliases, aliases are class names(Both capitals and lowercases are acceptable.)-->
        <package name="com.zhangguo.mybatis03.entities"></package>
    </typeAliases>

    <!--Register a custom type processor-->
    <typeHandlers>
        <!--<typeHandler handler="" javaType="" jdbcType=""></typeHandler>-->
    </typeHandlers>

    <!--Environmental configuration, default Environment selected for default-->
    <environments default="development">
        <!--Development-->
        <environment id="development">
            <!--transaction management-->
            <transactionManager type="JDBC"/>
            <!--Connection pool-->
            <dataSource type="POOLED">
                <!--Reference attribute ${mysql.driver}-->
                <property name="driver" value="${mysql.driver}"/>
                <property name="url" value="${mysql.url}"/>
                <property name="username" value="${mysql.username}"/>
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>
        <!--Function-->
        <environment id="work">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/nfmall?useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="uchr@123"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--Register one based on path XML Mapper-->
        <mapper resource="com/zhangguo/mybatis05/StudentMapper.xml"/>
    </mappers>

</configuration>

POJO:

package com.zhangguo.mybatis05.entities;

import java.io.Serializable;

/**
 * @author 
 */
public class Student implements Serializable {
    private Integer id;

    private String name;

    private String sex;

    private static final long serialVersionUID = 1L;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public boolean equals(Object that) {
        if (this == that) {
            return true;
        }
        if (that == null) {
            return false;
        }
        if (getClass() != that.getClass()) {
            return false;
        }
        Student other = (Student) that;
        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
            && (this.getName() == null ? other.getName() == null : this.getName().equals(other.getName()))
            && (this.getSex() == null ? other.getSex() == null : this.getSex().equals(other.getSex()));
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
        result = prime * result + ((getName() == null) ? 0 : getName().hashCode());
        result = prime * result + ((getSex() == null) ? 0 : getSex().hashCode());
        return result;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", id=").append(id);
        sb.append(", name=").append(name);
        sb.append(", sex=").append(sex);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
    }
}

Parameters:

package com.zhangguo.mybatis05.entities;

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

public class StudentExample {
    protected String orderByClause;

    protected boolean distinct;

    protected List<Criteria> oredCriteria;

    private Integer limit;

    private Integer offset;

    public StudentExample() {
        oredCriteria = new ArrayList<Criteria>();
    }

    public void setOrderByClause(String orderByClause) {
        this.orderByClause = orderByClause;
    }

    public String getOrderByClause() {
        return orderByClause;
    }

    public void setDistinct(boolean distinct) {
        this.distinct = distinct;
    }

    public boolean isDistinct() {
        return distinct;
    }

    public List<Criteria> getOredCriteria() {
        return oredCriteria;
    }

    public void or(Criteria criteria) {
        oredCriteria.add(criteria);
    }

    public Criteria or() {
        Criteria criteria = createCriteriaInternal();
        oredCriteria.add(criteria);
        return criteria;
    }

    public Criteria createCriteria() {
        Criteria criteria = createCriteriaInternal();
        if (oredCriteria.size() == 0) {
            oredCriteria.add(criteria);
        }
        return criteria;
    }

    protected Criteria createCriteriaInternal() {
        Criteria criteria = new Criteria();
        return criteria;
    }

    public void clear() {
        oredCriteria.clear();
        orderByClause = null;
        distinct = false;
    }

    public void setLimit(Integer limit) {
        this.limit = limit;
    }

    public Integer getLimit() {
        return limit;
    }

    public void setOffset(Integer offset) {
        this.offset = offset;
    }

    public Integer getOffset() {
        return offset;
    }

    protected abstract static class GeneratedCriteria {
        protected List<Criterion> criteria;

        protected GeneratedCriteria() {
            super();
            criteria = new ArrayList<Criterion>();
        }

        public boolean isValid() {
            return criteria.size() > 0;
        }

        public List<Criterion> getAllCriteria() {
            return criteria;
        }

        public List<Criterion> getCriteria() {
            return criteria;
        }

        protected void addCriterion(String condition) {
            if (condition == null) {
                throw new RuntimeException("Value for condition cannot be null");
            }
            criteria.add(new Criterion(condition));
        }

        protected void addCriterion(String condition, Object value, String property) {
            if (value == null) {
                throw new RuntimeException("Value for " + property + " cannot be null");
            }
            criteria.add(new Criterion(condition, value));
        }

        protected void addCriterion(String condition, Object value1, Object value2, String property) {
            if (value1 == null || value2 == null) {
                throw new RuntimeException("Between values for " + property + " cannot be null");
            }
            criteria.add(new Criterion(condition, value1, value2));
        }

        public Criteria andIdIsNull() {
            addCriterion("id is null");
            return (Criteria) this;
        }

        public Criteria andIdIsNotNull() {
            addCriterion("id is not null");
            return (Criteria) this;
        }

        public Criteria andIdEqualTo(Integer value) {
            addCriterion("id =", value, "id");
            return (Criteria) this;
        }

        public Criteria andIdNotEqualTo(Integer value) {
            addCriterion("id <>", value, "id");
            return (Criteria) this;
        }

        public Criteria andIdGreaterThan(Integer value) {
            addCriterion("id >", value, "id");
            return (Criteria) this;
        }

        public Criteria andIdGreaterThanOrEqualTo(Integer value) {
            addCriterion("id >=", value, "id");
            return (Criteria) this;
        }

        public Criteria andIdLessThan(Integer value) {
            addCriterion("id <", value, "id");
            return (Criteria) this;
        }

        public Criteria andIdLessThanOrEqualTo(Integer value) {
            addCriterion("id <=", value, "id");
            return (Criteria) this;
        }

        public Criteria andIdIn(List<Integer> values) {
            addCriterion("id in", values, "id");
            return (Criteria) this;
        }

        public Criteria andIdNotIn(List<Integer> values) {
            addCriterion("id not in", values, "id");
            return (Criteria) this;
        }

        public Criteria andIdBetween(Integer value1, Integer value2) {
            addCriterion("id between", value1, value2, "id");
            return (Criteria) this;
        }

        public Criteria andIdNotBetween(Integer value1, Integer value2) {
            addCriterion("id not between", value1, value2, "id");
            return (Criteria) this;
        }

        public Criteria andNameIsNull() {
            addCriterion("name is null");
            return (Criteria) this;
        }

        public Criteria andNameIsNotNull() {
            addCriterion("name is not null");
            return (Criteria) this;
        }

        public Criteria andNameEqualTo(String value) {
            addCriterion("name =", value, "name");
            return (Criteria) this;
        }

        public Criteria andNameNotEqualTo(String value) {
            addCriterion("name <>", value, "name");
            return (Criteria) this;
        }

        public Criteria andNameGreaterThan(String value) {
            addCriterion("name >", value, "name");
            return (Criteria) this;
        }

        public Criteria andNameGreaterThanOrEqualTo(String value) {
            addCriterion("name >=", value, "name");
            return (Criteria) this;
        }

        public Criteria andNameLessThan(String value) {
            addCriterion("name <", value, "name");
            return (Criteria) this;
        }

        public Criteria andNameLessThanOrEqualTo(String value) {
            addCriterion("name <=", value, "name");
            return (Criteria) this;
        }

        public Criteria andNameLike(String value) {
            addCriterion("name like", value, "name");
            return (Criteria) this;
        }

        public Criteria andNameNotLike(String value) {
            addCriterion("name not like", value, "name");
            return (Criteria) this;
        }

        public Criteria andNameIn(List<String> values) {
            addCriterion("name in", values, "name");
            return (Criteria) this;
        }

        public Criteria andNameNotIn(List<String> values) {
            addCriterion("name not in", values, "name");
            return (Criteria) this;
        }

        public Criteria andNameBetween(String value1, String value2) {
            addCriterion("name between", value1, value2, "name");
            return (Criteria) this;
        }

        public Criteria andNameNotBetween(String value1, String value2) {
            addCriterion("name not between", value1, value2, "name");
            return (Criteria) this;
        }

        public Criteria andSexIsNull() {
            addCriterion("sex is null");
            return (Criteria) this;
        }

        public Criteria andSexIsNotNull() {
            addCriterion("sex is not null");
            return (Criteria) this;
        }

        public Criteria andSexEqualTo(String value) {
            addCriterion("sex =", value, "sex");
            return (Criteria) this;
        }

        public Criteria andSexNotEqualTo(String value) {
            addCriterion("sex <>", value, "sex");
            return (Criteria) this;
        }

        public Criteria andSexGreaterThan(String value) {
            addCriterion("sex >", value, "sex");
            return (Criteria) this;
        }

        public Criteria andSexGreaterThanOrEqualTo(String value) {
            addCriterion("sex >=", value, "sex");
            return (Criteria) this;
        }

        public Criteria andSexLessThan(String value) {
            addCriterion("sex <", value, "sex");
            return (Criteria) this;
        }

        public Criteria andSexLessThanOrEqualTo(String value) {
            addCriterion("sex <=", value, "sex");
            return (Criteria) this;
        }

        public Criteria andSexLike(String value) {
            addCriterion("sex like", value, "sex");
            return (Criteria) this;
        }

        public Criteria andSexNotLike(String value) {
            addCriterion("sex not like", value, "sex");
            return (Criteria) this;
        }

        public Criteria andSexIn(List<String> values) {
            addCriterion("sex in", values, "sex");
            return (Criteria) this;
        }

        public Criteria andSexNotIn(List<String> values) {
            addCriterion("sex not in", values, "sex");
            return (Criteria) this;
        }

        public Criteria andSexBetween(String value1, String value2) {
            addCriterion("sex between", value1, value2, "sex");
            return (Criteria) this;
        }

        public Criteria andSexNotBetween(String value1, String value2) {
            addCriterion("sex not between", value1, value2, "sex");
            return (Criteria) this;
        }
    }

    /**
     */
    public static class Criteria extends GeneratedCriteria {

        protected Criteria() {
            super();
        }
    }

    public static class Criterion {
        private String condition;

        private Object value;

        private Object secondValue;

        private boolean noValue;

        private boolean singleValue;

        private boolean betweenValue;

        private boolean listValue;

        private String typeHandler;

        public String getCondition() {
            return condition;
        }

        public Object getValue() {
            return value;
        }

        public Object getSecondValue() {
            return secondValue;
        }

        public boolean isNoValue() {
            return noValue;
        }

        public boolean isSingleValue() {
            return singleValue;
        }

        public boolean isBetweenValue() {
            return betweenValue;
        }

        public boolean isListValue() {
            return listValue;
        }

        public String getTypeHandler() {
            return typeHandler;
        }

        protected Criterion(String condition) {
            super();
            this.condition = condition;
            this.typeHandler = null;
            this.noValue = true;
        }

        protected Criterion(String condition, Object value, String typeHandler) {
            super();
            this.condition = condition;
            this.value = value;
            this.typeHandler = typeHandler;
            if (value instanceof List<?>) {
                this.listValue = true;
            } else {
                this.singleValue = true;
            }
        }

        protected Criterion(String condition, Object value) {
            this(condition, value, null);
        }

        protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
            super();
            this.condition = condition;
            this.value = value;
            this.secondValue = secondValue;
            this.typeHandler = typeHandler;
            this.betweenValue = true;
        }

        protected Criterion(String condition, Object value, Object secondValue) {
            this(condition, value, secondValue, null);
        }
    }
}

Mapper:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhangguo.mybatis05.mapper.StudentMapper">
  <resultMap id="BaseResultMap" type="com.zhangguo.mybatis05.entities.Student">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="sex" jdbcType="CHAR" property="sex" />
  </resultMap>
  <sql id="Example_Where_Clause">
    <where>
      <foreach collection="oredCriteria" item="criteria" separator="or">
        <if test="criteria.valid">
          <trim prefix="(" prefixOverrides="and" suffix=")">
            <foreach collection="criteria.criteria" item="criterion">
              <choose>
                <when test="criterion.noValue">
                  and ${criterion.condition}
                </when>
                <when test="criterion.singleValue">
                  and ${criterion.condition} #{criterion.value}
                </when>
                <when test="criterion.betweenValue">
                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
                </when>
                <when test="criterion.listValue">
                  and ${criterion.condition}
                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
                    #{listItem}
                  </foreach>
                </when>
              </choose>
            </foreach>
          </trim>
        </if>
      </foreach>
    </where>
  </sql>
  <sql id="Update_By_Example_Where_Clause">
    <where>
      <foreach collection="example.oredCriteria" item="criteria" separator="or">
        <if test="criteria.valid">
          <trim prefix="(" prefixOverrides="and" suffix=")">
            <foreach collection="criteria.criteria" item="criterion">
              <choose>
                <when test="criterion.noValue">
                  and ${criterion.condition}
                </when>
                <when test="criterion.singleValue">
                  and ${criterion.condition} #{criterion.value}
                </when>
                <when test="criterion.betweenValue">
                  and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
                </when>
                <when test="criterion.listValue">
                  and ${criterion.condition}
                  <foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
                    #{listItem}
                  </foreach>
                </when>
              </choose>
            </foreach>
          </trim>
        </if>
      </foreach>
    </where>
  </sql>
  <sql id="Base_Column_List">
    id, name, sex
  </sql>
  <select id="selectByExample" parameterType="com.zhangguo.mybatis05.entities.StudentExample" resultMap="BaseResultMap">
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="Base_Column_List" />
    from student
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
    <if test="limit != null">
      <if test="offset != null">
        limit ${offset}, ${limit}
      </if>
      <if test="offset == null">
        limit ${limit}
      </if>
    </if>
  </select>
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from student
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from student
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <delete id="deleteByExample" parameterType="com.zhangguo.mybatis05.entities.StudentExample">
    delete from student
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
  </delete>
  <insert id="insert" parameterType="com.zhangguo.mybatis05.entities.Student">
    insert into student (id, name, sex)
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{sex,jdbcType=CHAR})
  </insert>
  <insert id="insertSelective" parameterType="com.zhangguo.mybatis05.entities.Student">
    insert into student
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="name != null">
        name,
      </if>
      <if test="sex != null">
        sex,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="name != null">
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="sex != null">
        #{sex,jdbcType=CHAR},
      </if>
    </trim>
  </insert>
  <select id="countByExample" parameterType="com.zhangguo.mybatis05.entities.StudentExample" resultType="java.lang.Long">
    select count(*) from student
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
  </select>
  <update id="updateByExampleSelective" parameterType="map">
    update student
    <set>
      <if test="record.id != null">
        id = #{record.id,jdbcType=INTEGER},
      </if>
      <if test="record.name != null">
        name = #{record.name,jdbcType=VARCHAR},
      </if>
      <if test="record.sex != null">
        sex = #{record.sex,jdbcType=CHAR},
      </if>
    </set>
    <if test="_parameter != null">
      <include refid="Update_By_Example_Where_Clause" />
    </if>
  </update>
  <update id="updateByExample" parameterType="map">
    update student
    set id = #{record.id,jdbcType=INTEGER},
      name = #{record.name,jdbcType=VARCHAR},
      sex = #{record.sex,jdbcType=CHAR}
    <if test="_parameter != null">
      <include refid="Update_By_Example_Where_Clause" />
    </if>
  </update>
  <update id="updateByPrimaryKeySelective" parameterType="com.zhangguo.mybatis05.entities.Student">
    update student
    <set>
      <if test="name != null">
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="sex != null">
        sex = #{sex,jdbcType=CHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.zhangguo.mybatis05.entities.Student">
    update student
    set name = #{name,jdbcType=VARCHAR},
      sex = #{sex,jdbcType=CHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

Interface:

package com.zhangguo.mybatis05.mapper;

import com.zhangguo.mybatis05.entities.Student;
import com.zhangguo.mybatis05.entities.StudentExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;

public interface StudentMapper {
    long countByExample(StudentExample example);

    int deleteByExample(StudentExample example);

    int deleteByPrimaryKey(Integer id);

    int insert(Student record);

    int insertSelective(Student record);

    List<Student> selectByExample(StudentExample example);

    Student selectByPrimaryKey(Integer id);

    int updateByExampleSelective(@Param("record") Student record, @Param("example") StudentExample example);

    int updateByExample(@Param("record") Student record, @Param("example") StudentExample example);

    int updateByPrimaryKeySelective(Student record);

    int updateByPrimaryKey(Student record);
}

Data access class:

package com.zhangguo.mybatis05.dao;

import com.zhangguo.mybatis05.entities.Student;
import com.zhangguo.mybatis05.entities.StudentExample;
import com.zhangguo.mybatis05.utils.SqlSessionFactoryUtils;
import com.zhangguo.mybatis05.mapper.StudentMapper;
import org.apache.ibatis.session.SqlSession;

import java.util.List;
import java.util.Map;

public class StudentDao implements StudentMapper {


    public long countByExample(StudentExample example) {
        return 0;
    }

    public int deleteByExample(StudentExample example) {
        return 0;
    }

    public int deleteByPrimaryKey(Integer id) {
        return 0;
    }

    public int insert(Student record) {
        return 0;
    }

    public int insertSelective(Student record) {
        return 0;
    }

    public List<Student> selectByExample(StudentExample example) {
        List<Student>  entities = null;
        //Open a session
        SqlSession session = SqlSessionFactoryUtils.openSqlSession(true);

        //Get a mapper
        StudentMapper mapper = session.getMapper(StudentMapper.class);

        //Query multiple objects
        entities = mapper.selectByExample(example);

        //Close
        SqlSessionFactoryUtils.closeSession(session);

        return entities;
    }

    public Student selectByPrimaryKey(Integer id) {
        return null;
    }

    public int updateByExampleSelective(Student record, StudentExample example) {
        return 0;
    }

    public int updateByExample(Student record, StudentExample example) {
        return 0;
    }

    public int updateByPrimaryKeySelective(Student record) {
        return 0;
    }

    public int updateByPrimaryKey(Student record) {
        return 0;
    }
}

Unit testing:

package com.zhangguo.mybatis05.dao;

import com.zhangguo.mybatis05.entities.Student;
import com.zhangguo.mybatis05.entities.StudentExample;
import org.junit.Test;
import org.junit.Before;
import org.junit.After;

import java.util.List;

/**
 * StudentDao Tester.
 *
 * @author <Authors name>
 * @version 1.0
 * @since <pre>10/09/2018</pre>
 */
public class StudentDaoTest {

    StudentDao dao;

    @Before
    public void before() throws Exception {
        dao = new StudentDao();
    }

    @After
    public void after() throws Exception {
    }

    /**
     * Method: countByExample(StudentExample example)
     */
    @Test
    public void testCountByExample() throws Exception {
//TODO: Test goes here... 
    }

    /**
     * Method: deleteByExample(StudentExample example)
     */
    @Test
    public void testDeleteByExample() throws Exception {
//TODO: Test goes here... 
    }

    /**
     * Method: deleteByPrimaryKey(Integer id)
     */
    @Test
    public void testDeleteByPrimaryKey() throws Exception {
//TODO: Test goes here... 
    }

    /**
     * Method: insert(Student record)
     */
    @Test
    public void testInsert() throws Exception {
//TODO: Test goes here... 
    }

    /**
     * Method: insertSelective(Student record)
     */
    @Test
    public void testInsertSelective() throws Exception {
//TODO: Test goes here... 
    }

    /**
     * Method: selectByExample(StudentExample example)
     */
    @Test
    public void testSelectByExample() throws Exception {
        StudentExample se = new StudentExample();

        se.createCriteria().andIdBetween(3, 5);

        List<Student> students = dao.selectByExample(se);
        System.out.println(students);
    }

    /**
     * Method: selectByPrimaryKey(Integer id)
     */
    @Test
    public void testSelectByPrimaryKey() throws Exception {
//TODO: Test goes here... 
    }

    /**
     * Method: updateByExampleSelective(Student record, StudentExample example)
     */
    @Test
    public void testUpdateByExampleSelective() throws Exception {
//TODO: Test goes here... 
    }

    /**
     * Method: updateByExample(Student record, StudentExample example)
     */
    @Test
    public void testUpdateByExample() throws Exception {
//TODO: Test goes here... 
    }

    /**
     * Method: updateByPrimaryKeySelective(Student record)
     */
    @Test
    public void testUpdateByPrimaryKeySelective() throws Exception {
//TODO: Test goes here... 
    }

    /**
     * Method: updateByPrimaryKey(Student record)
     */
    @Test
    public void testUpdateByPrimaryKey() throws Exception {
//TODO: Test goes here... 
    }


} 

Operation results:

Other GUI tools:

https://github.com/spawpaw/mybatis-generator-gui-extension

mybatis-generator-gui-extension is a graphical interface written for Mybatis Generator, which provides rich extensions for entity/Example/Mapper.

https://github.com/xialeistudio/mybatis-generator-gui
Visual mybatis generation tool

[https://www.oschina.net/p/mybatis-generator-gui]

4. Sample source code

https://git.dev.tencent.com/zhangguo5/MyBatis06.git

https://git.coding.net/zhangguo5/MyBatis03.git

https://git.coding.net/zhangguo5/MyBatis02.git

Five, video

https://www.bilibili.com/video/av32447485/

6. Major assignments

Summary:

In Yunnan, China, there is a beautiful place called Ruili, where there are abundant jade ornaments. In order to develop the network economy and open up the market, a company called Ruili Yuyuan has built an e-commerce website. It requires that the website can search for goods according to various conditions, and filter products according to different conditions at the same time, including brand, price, color, water type, mosaic, implication and so on. The widget type.

Functional requirements:

1. The Data to be displayed has been given. Under the material and dataData folder, there are Data in the format of MSSQL Server database SouthMall, SQL script and Excel. The Data needed can be obtained in any way.

2. There is a commodity table named Products in the database. The structure of the table is shown in Table 3-1.

Serial number

Column names

Explain

data type

length

Decimal place

Identification

Primary key

Allow space

1

Id

number

int

4

0

 

yes

no

2

Name

Trade name

nvarchar

255

0

 

 

yes

3

Color

colour

nvarchar

500

0

 

 

yes

4

BrandId

brand

int

4

0

 

 

yes

5

InLayId

Set

Int

4

0

 

 

yes

6

MoralId

Moral

Int

4

0

 

 

yes

7

IceTypeId

Cultivate land

Int

4

0

 

 

yes

8

HangTypeId

Pendant type

int

4

0

 

 

yes

9

MarketPrice

market price

float

8

0

 

 

yes

10

MyPrice

Mall price

float

8

0

 

 

yes

11

Picture

picture

nvarchar

255

0

 

 

yes

Table 3-1

Please use Color, Brand, InLay, Moral, IceType and HangType as foreign keys and break them into seven tables.

3. The default state is to select all the conditions, as shown in Figure 3-1, that is, to show all the goods.

Figure 3-1

4. When users click on different conditions, they can filter out the corresponding results by various combinations. The selected conditions should be highlighted, but not all of them should be checked (one is checked.jpg, the other is unchecked.jpg, which is stored in the material and data / UI picture catalogue) as shown in Figure 3-2.

 

Figure 3-2

Technical implementation:

1. In order to avoid refreshing the whole page when considering the changing conditions of user experience, AJAX can be used. jQuery library files are stored in the material and data / Scripts directory. Please do not use ASP.NET AJAX technology (Microsoft Packaged Server AJAX technology).

2. Search conditions should be dynamically generated according to the database, with the exception of price.

3. If you use ASP.NET WebForms technology to achieve, the page can not appear ViewState (page state), please disable the control and page state (EnableViewState="false").

4. You can use any B/S technology, such as. NET, Java or Web technology under PHP platform.

5. Except for the specified requirements, do not make special requirements for UI, such as color, layout and font, basic regularity can be. All materials used by UI are saved in the material and data folder.

6. Data access is not restricted. Any ORM framework or database access components, such as JDB, MyBatis, Hibernate, LINQ to SQL/Entity, Entity Framework, ADO.NET, can be used.

Common:

paging

Background add

Module Block, Maven, Git

Senior:

Adding multi-field sorting on the basis of common (sorting type and ascending or descending order can be selected)

CRUD

Material download: https://git.dev.tencent.com/zhangguo5/MyBatis06.git

Posted by adrian28uk on Sat, 11 May 2019 16:07:26 -0700