MyBatis学习总结(四)——MyBatis缓存与代码生成


 一、MyBatis缓存

缓存可以提高系统性能,可以加快访问速度,减轻服务器压力,带来更好的用户体验。缓存用空间换时间,好的缓存是缓存命中率高的且数据量小的。缓存是一种非常重要的技术。

1.0、再次封装SqlSessionFactoryUtils

为了配置缓存的学习我们将工具类再次封装。

原SqlSessionFactoryUtil工具类如下:

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 会话工具类
 * */
public class SqlSessionFactoryUtil {

    /**
     * 获得会话工厂
     *
     * */
    public static SqlSessionFactory getFactory(){
        InputStream inputStream = null;
        SqlSessionFactory sqlSessionFactory=null;
        try{
            //加载conf.xml配置文件,转换成输入流
            inputStream = SqlSessionFactoryUtil.class.getClassLoader().getResourceAsStream("mybatisCfg.xml");

            //根据配置文件的输入流构造一个SQL会话工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
        finally {
            if(inputStream!=null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sqlSessionFactory;
    }

    /**
     * 获得sql会话,是否自动提交
     * */
    public static SqlSession openSession(boolean isAutoCommit){
        return getFactory().openSession(isAutoCommit);
    }

    /**
     * 关闭会话
     * */
    public static void closeSession(SqlSession session){
        if(session!=null){
            session.close();
        }
    }

}

上面的代码中当我们每次获取SQLSession时都要实例化sqlSessionFactory,效率不高。可以使用单例改进:

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会话工具类
 * */
public class SqlSessionFactoryUtils {

    /**会话工厂*/
    private static SqlSessionFactory factory;

    static {
        try {
            /*获得配置文件的文件流*/
           InputStream inputStream=Resources.getResourceAsStream("mybatisCfg.xml");
           //初始化工厂
            factory=new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得会话对象
     * 指定是否自动提交
     * */
    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;
    }

    /**
     * 关闭会话
     * */
    public static void closeSession(SqlSession session){
        if(session!=null){
            session.close();
        }
    }
}

1.1、MyBatis缓存概要

在一个系统中查询的频次远远高于增删改,据三方统计不同系统比例在9:1-7:3之间。正如大多数持久层框架一样,MyBatis 同样提供了一级缓存二级缓存的支持

(1)、一级缓存基于PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session flush close 之后,该Session中的所有 Cache 就将清空

(2)、二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace)并且可自定义存储源,如 Ehcache。

(3)、对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

1.2、默认MyBatis的一级缓存是开启的

测试用例:

    /**缓存测试*/
    @Test
    public void cacheTest(){
        //打开一个会话,不自动提交
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //获得一个映射器
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //查询单个对象通过编号
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);
        
        Student student2 = mapper1.selectStudentById(1);
        System.out.println(student2);
        //关闭
        SqlSessionFactoryUtils.closeSession(session1);
    }

结果:

虽然查询了二次,但只向数据库发送了一次SQL请求,因为第二次是在缓存中获得的数据。

1.3、一级缓存仅在同一个会话(SQLSession)中有效

测试用例:

    /**缓存测试*/
    @Test
    public void cacheTest(){
        //打开一个会话1,不自动提交
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //获得一个映射器
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //查询单个对象通过编号
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);

        //打开一个会话2,不自动提交
        SqlSession session2 = SqlSessionFactoryUtils.openSqlSession(false);
        //获得一个映射器
        StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
        Student student2 = mapper2.selectStudentById(1);
        System.out.println(student2);
        //关闭
        SqlSessionFactoryUtils.closeSession(session1);
    }

结果:

从上图可以看出此时并没有使用缓存,向数据库查询了二次,因为第二次查询使用的是新的会话,而一级缓存必须在同一个会话中。

1.4、清空一级缓存

(1)、当对表执行增删改时缓存将清空

测试用例:

    /**缓存测试*/
    @Test
    public void cacheTest(){
        //打开一个会话1,不自动提交
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //获得一个映射器
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //查询单个对象通过编号
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);

        //执行更新
        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);
    }

结果:

从日志中可以看出第二次查询也发送了sql到数据库中,并没有使用缓存,是因为执行了更新操作缓存已被清空。

此时数据库中的数据其实并未真的更新,如下所示:

因为没有手动提交,可以设置自动提交

/**缓存测试*/
    @Test
    public void cacheTest(){
        //打开一个会话1,不自动提交
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //获得一个映射器
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //查询单个对象通过编号
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);

        //执行更新
        Student lili=new Student();
        lili.setId(5);
        lili.setSex("girl");
        mapper1.updateStudent(lili);

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

        //提交
        session1.commit();
        SqlSessionFactoryUtils.closeSession(session1);
    }

提交后的结果

(2)、手动清空

测试用例:

   /**缓存测试*/
    @Test
    public void cacheTest(){
        //打开一个会话1,不自动提交
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //获得一个映射器
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //查询单个对象通过编号
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);

        //执行手动更新
        session1.clearCache();

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

        //提交
        session1.commit();
        SqlSessionFactoryUtils.closeSession(session1);
    }

结果:

从日志中可以看到第二次查询并未使用缓存因为执行了手动清空缓存,没有缓存可用则再次查询数据库。

小结:当Session flush或close之后,该Session中的所有 Cache 就将清空;执行CUD也将会自动清空;手动清空;

1.5、开启二级缓存

默认二级缓存是不开启的,需要手动进行配置

1.5.1、全局开关

默认是true,如果它配成false,其余各个Mapper XML文件配成支持cache也没用。

    <settings>
        
        <setting name="cacheEnabled" value="true"/>
        
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    settings>

1.5.2、单个Mapper XML映射文件开关

默认Mapper XML映射文件是不采用cache。在配置文件加一行就可以支持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">

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

可以在开启二级缓存时候,手动配置一些属性

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

各个属性意义如下:

  • eviction:缓存回收策略
    - LRU:最少使用原则,移除最长时间不使用的对象
    - FIFO:先进先出原则,按照对象进入缓存顺序进行回收
    - SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
    - WEAK:弱引用,更积极的移除移除基于垃圾回收器状态和弱引用规则的对象
  • flushInterval:刷新时间间隔,单位为毫秒,这里配置的100毫秒。如果不配置,那么只有在进行数据库修改操作才会被动刷新缓存区
  • size:引用额数目,代表缓存最多可以存储的对象个数
  • readOnly:是否只读,如果为true,则所有相同的sql语句返回的是同一个对象(有助于提高性能,但并发操作同一条数据时,可能不安全),如果设置为false,则相同的sql,后面访问的是cache的clone副本。

1.5.3、Mapper statement开关

Mapper XML文件配置支持cache后,文件中所有的Mapper statement就支持了。此时要个别对待某条,需要:
<select id="selectStudentById" resultType="Student" useCache="false">
    SELECT id,name,sex from student where id=#{id}
select>

可以在Mapper的具体方法下设置对二级缓存的访问意愿:

  • useCache配置

    ? 如果一条语句每次都需要最新的数据,就意味着每次都需要从数据库中查询数据,可以把这个属性设置为false,如:

<select id="selectAll" useCache="false">
  • 刷新缓存(就是清空缓存)

    ? 二级缓存默认会在insert、update、delete操作后刷新缓存,可以手动配置不更新缓存,如下:

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

1.5.4、实现可序列化接口

 如果未实现可序列化接口,会引发异常。

修改POJO对象,增加实现可序列化接口:

package com.zhangguo.mybatis03.entities;

import java.io.Serializable;

/**
 * 学生实体
 */
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、注意事项

1、如果readOnly为false,此时要结果集对象是可序列化的。
<cache readOnly="false"/>
2、在SqlSession未关闭之前,如果对于同样条件进行重复查询,此时采用的是local session cache,而不是上面说的这些cache。 3、MyBatis缓存查询到的结果集对象,而非结果集数据,是将映射的POJO对象集合缓存起来。 4、面对一定规模的数据量,内置的cache方式就派不上用场了; 5、对查询结果集做缓存并不是MyBatis框架擅长的,它专心做的应该是sql mapper。采用此框架的Application去构建缓存更合理,比如采用Redis、Ehcache、OSCache、Memcached等

当我们的配置文件配置了cacheEnabled=true时,就会开启二级缓存,二级缓存是mapper级别的,也就说不同的sqlsession使用同一个mapper查询是,查询到的数据可能是另一个sqlsession做相同操作留下的缓存。

查询数据的顺序为:二级缓存 -> 一级缓存 -> 数据库

1.6、二级缓存测试

默认情况下一级缓存只在同一个会话中有效:

用例:

    /**缓存测试*/
    @Test
    public void cacheTest(){
        //打开一个会话1,不自动提交
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //获得一个映射器1
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //查询单个对象通过编号
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);
        
        //打开一个会话2,不自动提交
        SqlSession session2 = SqlSessionFactoryUtils.openSqlSession(false);
        //获得一个映射器2
        StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
        //查询单个对象通过编号
        Student student2 = mapper2.selectStudentById(1);
        System.out.println(student2);

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

结果:

如果需要将范围扩大到同一个namespace中有效可以使用二级缓存:

用例:

    /**缓存测试*/
    @Test
    public void cacheTest(){
        //打开一个会话1,不自动提交
        SqlSession session1 = SqlSessionFactoryUtils.openSqlSession(false);
        //获得一个映射器1
        StudentMapper mapper1 = session1.getMapper(StudentMapper.class);
        //查询单个对象通过编号
        Student student1 = mapper1.selectStudentById(1);
        System.out.println(student1);

        //必须手动提交,否则无效
        session1.commit();

        //打开一个会话2,不自动提交
        SqlSession session2 = SqlSessionFactoryUtils.openSqlSession(false);
        //获得一个映射器2
        StudentMapper mapper2 = session2.getMapper(StudentMapper.class);
        //查询单个对象通过编号
        Student student2 = mapper2.selectStudentById(1);
        System.out.println(student2);

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

结果:

如果不手动提交查询结果也不会缓存成功。

使用两个不同的SqlSession对象去执行相同查询条件的查询,第二次查询时不会再发送SQL语句,而是直接从缓存中取出数据

1.7、二级缓存小结

  1. 映射语句文件中的所有select语句将会被缓存。

  2. 映射语句文件中的所有insert,update和delete语句会刷新缓存。

  3. 缓存会使用Least Recently Used(LRU,最近最少使用的)算法来收回。

  4. 缓存会根据指定的时间间隔来刷新。

  5. 缓存会存储1024个对象

cache标签常用属性:

<cache 
eviction="FIFO"  
size="512" 
readOnly="true"/> 

二、MyBatis-Generator代码生成

2.1、在Intellij IDEA创建maven项目

这里创建了一个Maven项目,未使用骨架。

2.2、添加依赖

在maven项目的pom.xml 添加mybatis-generator-maven-plugin 插件

<?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.0modelVersion>

    <groupId>com.zhangguo.mybatis06groupId>
    <artifactId>MyBatis06artifactId>
    <version>1.0-SNAPSHOTversion>

    <dependencies>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.4.6version>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.38version>
        dependency>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.11version>
            <scope>testscope>
        dependency>
        
        <dependency>
            <groupId>org.mybatis.generatorgroupId>
            <artifactId>mybatis-generator-coreartifactId>
            <version>1.3.5version>
        dependency>
    dependencies>


    
    <build>
        <finalName>MyBatis06finalName>
        <plugins>
            <plugin>
                <groupId>org.mybatis.generatorgroupId>
                <artifactId>mybatis-generator-maven-pluginartifactId>
                <version>1.3.2version>
                <configuration>
                    <verbose>trueverbose>
                    <overwrite>trueoverwrite>
                configuration>
            plugin>
        plugins>
    build>
project>

2.3、配置生成参数

在maven项目下的src/main/resources 目录下建立名为 generatorConfig.xml的配置文件,作为mybatis-generator-maven-plugin 插件的执行目标:

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

    
    <properties resource="db.properties">properties>

    
    <classPathEntry location="${mysql.driverLocation}"/>

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

        
        <commentGenerator>
            <property name="suppressDate" value="true" />
        commentGenerator>

        
        <jdbcConnection driverClass="${mysql.driver}" connectionURL="${mysql.url}" userId="${mysql.username}" password="${mysql.password}">
        jdbcConnection>

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

        
        <javaModelGenerator targetPackage="com.zhangguo.mybatis06.entities" targetProject="src/main/java">
            
            <property name="constructorBased" value="true"/>

            
            <property name="enableSubPackages" value="false"/>

            
            <property name="immutable" value="true"/>

            
            <property name="rootClass" value="com.zhangguo.mybatis06.entities.BaseEntity"/>

            
            <property name="trimStrings" value="true"/>
        javaModelGenerator>

        
        <sqlMapGenerator targetPackage="com.zhangguo.mybatis06.mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="false"/>
        sqlMapGenerator>


        
        <javaClientGenerator targetPackage="com.zhangguo.mybatis06.dao" targetProject="src/main/java" type="MIXEDMAPPER">
            <property name="enableSubPackages" value=""/>
            
            <property name="exampleMethodVisibility" value=""/>
            
            <property name="methodNameCalculator" value=""/>

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

这里的属性资源文件与mybatis共用db.propities文件

##MySQL连接字符串
#驱动
mysql.driver=com.mysql.jdbc.Driver
#地址
mysql.url=jdbc:mysql://127.0.0.1:3306/nfmall?useUnicode=true&characterEncoding=UTF-8
#用户名
mysql.username=root
#密码
mysql.password=uchr@123
#驱动位置
mysql.driverLocation=E:\\NF\\Java\\JDBC\\mysql-connector-java-5.1.47\\mysql-connector-java-5.1.47.jar

参数配置文件一:

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

    
    <classPathEntry location=""/>

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

        
        <jdbcConnection driverClass="" connectionURL="" userId="" password=""/>

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

        
        <javaModelGenerator targetPackage="目标包" targetProject="目标项目classpath">
            <property name="enableSubPackages" value="false"/>
            <property name="trimStrings" value="true"/>
        javaModelGenerator>

        
        <sqlMapGenerator targetPackage="目标包" targetProject="目标项目classpath">
            <property name="enableSubPackages" value="false"/>
        sqlMapGenerator>

        
        <javaClientGenerator targetPackage="目标包" targetProject="目标项目classpath" type="XMLMAPPER">
            <property name="enableSubPackages" value="false"/>
        javaClientGenerator>

        
        <table tableName="表名" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
               enableUpdateByExample="false"/>
    context>
generatorConfiguration>

参考配置文件二:

<?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>  
      
    <properties resource="generator.properties">properties>  
  
      
    <classPathEntry location="${jdbc.driverLocation}"/>  
  
    <context id="default" targetRuntime="MyBatis3">  
  
  
          
        <commentGenerator>  
            <property name="suppressDate" value="true" />  
        commentGenerator>  
  
  
          
        <jdbcConnection driverClass="${jdbc.driverClass}" connectionURL="${jdbc.connectionURL}" userId="${jdbc.userId}" password="${jdbc.password}">  
        jdbcConnection>  
  
  
  
          
        <javaTypeResolver >  
            <property name="forceBigDecimals" value="false" />  
        javaTypeResolver>  
  
          
        <javaModelGenerator targetPackage="org.louis.hometutor.po" targetProject="src/main/java">  
              
            <property name="constructorBased" value="true"/>  
  
              
            <property name="enableSubPackages" value="false"/>  
  
              
            <property name="immutable" value="true"/>  
  
              
            <property name="rootClass" value="com.foo.louis.Hello"/>  
  
              
            <property name="trimStrings" value="true"/>  
        javaModelGenerator>  
  
          
        <sqlMapGenerator targetPackage="org.louis.hometutor.domain" targetProject="src/main/java">  
            <property name="enableSubPackages" value="false"/>  
        sqlMapGenerator>  
  
  
          
        <javaClientGenerator targetPackage="com.foo.tourist.dao" targetProject="src/main/java" type="MIXEDMAPPER">  
            <property name="enableSubPackages" value=""/>  
              
            <property name="exampleMethodVisibility" value=""/>  
              
            <property name="methodNameCalculator" value=""/>  
  
              
            <property name="rootInterface" value=""/>  
  
        javaClientGenerator>  
  
  
  
        <table tableName="lession" schema="louis">  
  
              
            <generatedKey column="" sqlStatement="" identity="" type=""/>  
  
  
              
            <columnRenamingRule searchString="" replaceString=""/>  
  
  
  
              
            <ignoreColumn column="PLAN_ID"  delimitedColumnName="true" />  
  
  
              
            <columnOverride column="" javaType=""    jdbcType="" typeHandler=""  delimitedColumnName="" />  
  
        table>  
    context>  
generatorConfiguration>  

属性资源文件:

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

这里使用了外置的配置文件generator.properties,可以将一下属性配置到properties文件之中,增加配置的灵活性:

项目目录如下:

2.4、执行生成

在Maven Projects中找到Plugins->mybatis-generator->mybatis-generator:generate

点击运行,然后不出意外的话,会在控制台输出:

[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] ------------------------------------------------------------------------

看到BUILD SUCCESS,则大功告成,如果有错误的话,由于添加了-e 选项,会把具体的详细错误信息打印出来的,根据错误信息修改即可。

生成结果:

2.5、使用生成的代码

1、MyBatis会话工具类

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会话工具类
 * */
public class SqlSessionFactoryUtils {

    /**会话工厂*/
    private static SqlSessionFactory factory;

    static {
        try {
            /*获得配置文件的文件流*/
           InputStream inputStream=Resources.getResourceAsStream("mybatisCfg.xml");
           //初始化工厂
            factory=new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得会话对象
     * 指定是否自动提交
     * */
    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;
    }

    /**
     * 关闭会话
     * */
    public static void closeSession(SqlSession session){
        if(session!=null){
            session.close();
        }
    }
}

2、MyBatis核心配置文件

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

    
    
    
        
        
    

    
        
        
        
        
    

    
    
        
        
        
        <package name="com.zhangguo.mybatis03.entities">package>
    

    
    
        
    

    
    default="development">
        
        
            
            
            
            
                
                
                
                
                
            
        
        
        
            
            
                
                
                
                
            
        
    

    
        
        

    

3、测试用例

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 selectByExample(StudentExample example);
     */
    @Test
    public void testSelectByExample(){

        List entities = null;
        //打开一个会话
        SqlSession session = SqlSessionFactoryUtils.openSqlSession(true);

        //获得一个映射器
        StudentMapper mapper = session.getMapper(StudentMapper.class);

        StudentExample studentExample=new StudentExample();
        //查询名字中含a
        studentExample.createCriteria().andNameLike("%a%");

        //查询多个对象,指定参数
        entities = mapper.selectByExample(studentExample);
        //关闭
        SqlSessionFactoryUtils.closeSession(session);

    }

}

测试结果:

三、MyBatis-GUI代码生成器mybatis-generator-gui

3.1、概要

源码地址:https://github.com/zouzg/mybatis-generator-gui

mybatis-generator-gui是基于mybatis generator开发一款界面工具, 本工具可以使你非常容易及快速生成Mybatis的Java POJO文件及数据库Mapping文件。

3.2、核心特性

  • 按照界面步骤轻松生成代码,省去XML繁琐的学习与配置过程
  • 保存数据库连接与Generator配置,每次代码生成轻松搞定
  • 内置常用插件,比如分页插件
  • 把数据库中表列的注释生成为Java实体的注释,生成的实体清晰明了
  • 可选的去除掉对版本管理不友好的注释,这样新增或删除字段重新生成的文件比较过来清楚
  • 目前已经支持Mysql、Mysql8、Oracle、PostgreSQL与SQL Server,暂不对其他非主流数据库提供支持。

3.3、要求

本工具由于使用了Java 8的众多特性,所以要求JDK 1.8.0.60以上版本,另外JDK 1.9暂时还不支持。

3.4、下载

你可以从本链接下载本工具: https://github.com/astarring/mybatis-generator-gui/releases

3.5、启动本软件

  • 方法一: 自助构建(注意项目名称需要根据实例情况修改
    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
  • 方法二: IDE中运行

Eclipse or IntelliJ IDEA中启动, 找到com.zzg.mybatis.generator.MainUI类并运行就可以了

  • 方法三:打包为本地原生应用,双击快捷方式即可启动,方便快捷

    如果不想打包后的安装包logo为Java的灰色的茶杯,需要在pom文件里将对应操作系统平台的图标注释放开

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

? 另外需要注意,windows系统打包成exe的话需要安装WiXToolset3+的环境;由于打包后会把jre打入安装包,两个平台均100M左右,体积较大请自行打包;打包后的安装包在target/jfx/native目录下

3.6、注意事项

  • 本自动生成代码工具只适合生成单表的增删改查,对于需要做数据库联合查询的,请自行写新的XML与Mapper;
  • 部分系统在中文输入方法时输入框中无法输入文字,请切换成英文输入法;
  • 如果不明白对应字段或选项是什么意思的时候,把光标放在对应字段或Label上停留一会然后如果有解释会出现解释;

3.7、文档

更多详细文档请参考本库的Wiki

  • Usage

3.8、代码生成示例

3.8.1、创建一个Maven项目

3.8.2、下载源代码并使用IDEA打开

下载地址:https://github.com/zouzg/mybatis-generator-gui/releases

解压后引入到IDEA中

找到MainUI类

3.8.3、运行程序

3.8.4、连接到数据

3.8.5、生成代码

3.8.6、使用生成的代码

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.0modelVersion>

    <groupId>com.zhangguo.mybatis05groupId>
    <artifactId>MyBatis05artifactId>
    <version>1.0-SNAPSHOTversion>

    <dependencies>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.4.6version>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.38version>
        dependency>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.11version>
            <scope>testscope>
        dependency>
    dependencies>
project>

工具类:

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会话工具类
 * */
public class SqlSessionFactoryUtils {

    /**会话工厂*/
    private static SqlSessionFactory factory;

    static {
        try {
            /*获得配置文件的文件流*/
           InputStream inputStream=Resources.getResourceAsStream("mybatisCfg.xml");
           //初始化工厂
            factory=new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得会话对象
     * 指定是否自动提交
     * */
    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;
    }

    /**
     * 关闭会话
     * */
    public static void closeSession(SqlSession session){
        if(session!=null){
            session.close();
        }
    }
}

核心配置文件:

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

    
    
    
        
        
    

    
        
        
        
        
    

    
    
        
        
        
        <package name="com.zhangguo.mybatis03.entities">package>
    

    
    
        
    

    
    default="development">
        
        
            
            
            
            
                
                
                
                
                
            
        
        
        
            
            
                
                
                
                
            
        
    

    
        
        
    

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

参数:

package com.zhangguo.mybatis05.entities;

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

public class StudentExample {
    protected String orderByClause;

    protected boolean distinct;

    protected List oredCriteria;

    private Integer limit;

    private Integer offset;

    public StudentExample() {
        oredCriteria = new ArrayList();
    }

    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 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 criteria;

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

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

        public List getAllCriteria() {
            return criteria;
        }

        public List 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 values) {
            addCriterion("id in", values, "id");
            return (Criteria) this;
        }

        public Criteria andIdNotIn(List 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 values) {
            addCriterion("name in", values, "name");
            return (Criteria) this;
        }

        public Criteria andNameNotIn(List 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 values) {
            addCriterion("sex in", values, "sex");
            return (Criteria) this;
        }

        public Criteria andSexNotIn(List 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);
        }
    }
}

映射器:

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

接口:

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 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);
}

数据访问类:

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 selectByExample(StudentExample example) {
        List  entities = null;
        //打开一个会话
        SqlSession session = SqlSessionFactoryUtils.openSqlSession(true);

        //获得一个映射器
        StudentMapper mapper = session.getMapper(StudentMapper.class);

        //查询多个对象
        entities = mapper.selectByExample(example);

        //关闭
        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;
    }
}

单元测试:

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 
 * @version 1.0
 * @since 
10/09/2018
*/ 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 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... } }

运行结果:

其它GUI工具:

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

mybatis-generator-gui-extension是一个为MybatisGenerator编写的图形化界面,为实体/Example/Mapper提供了丰富的扩展。

https://github.com/xialeistudio/mybatis-generator-gui
可视化mybatis生成工具

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

四、示例源代码

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

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

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

五、视频

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

六、大作业 

概述:

在中国云南有一个美丽的地方叫瑞丽,那里盛产玉饰,为了发展网络经济打开销路,有一家叫瑞丽玉源的公司搭建了一个电子商务网站,要求网站中可以按多种条件对商品进行搜索,可以同时按照多个条件进行过滤,包括:品牌、价格、颜色、水种、镶嵌、寓意和挂件类型。

功能需求:

1、要展示的数据已给出,在素材与数据\Data文件夹下有MSSQL Server数据库SouthMall、SQL脚本与Excel格式的数据,使用其中任意方式可以获得需要的数据。

2、数据库中有一个名为Products的商品表,表结构如表3-1所示:

序号

列名

说明

数据类型

长度

小数位

标识

主键

允许空

1

Id

编号

int

4

0

 

2

Name

商品名称

nvarchar

255

0

 

 

3

Color

颜色

nvarchar

500

0

 

 

4

BrandId

品牌

int

4

0

 

 

5

InLayId

镶嵌

Int

4

0

 

 

6

MoralId

寓意

Int

4

0

 

 

7

IceTypeId

种地

Int

4

0

 

 

8

HangTypeId

挂件类型

int

4

0

 

 

9

MarketPrice

市场价格

float

8

0

 

 

10

MyPrice

商城价格

float

8

0

 

 

11

Picture

图片

nvarchar

255

0

 

 

表3-1

请将Color、Brand、InLay、Moral、IceType、HangType作成外键,拆分成7张表

3、默认状态为所有条件都选择全部,如图3-1所示,即展示所有商品;

图 3-1

4、当用户点击不同的条件时可以进行多种组合过滤出相应结果,被选择条件项应该高亮显示,而这时不应该勾选全部(这里使用了两张图片,一张是选择全部checked.jpg,一张是未选择全部unchecked.jpg,存放在素材与数据/UI图片目录中)如图3-2所示;

 

图3-2 

技术实现:

1、为了考虑用户体验变换条件时不能刷新整页,可考虑使用AJAX。jQuery库文件已存放在素材与数据/Scripts目录下,请不要使用ASP.NET AJAX技术(微软封装的服务器AJAX技术)。

2、搜索条件应该根据数据库动态生成,价格除外。

3、如果使用ASP.NET WebForms技术实现,页面中不能出现ViewState(页面状态),请禁用控件与页面的状态(EnableViewState="false")。

4、可以使用任意B/S技术,如.NET,Java或PHP平台下的Web技术。

5、除指定要求外,不对UI作特殊要求,如色彩、布局与字体等,基本规整就可以。UI用到的所有素材已保存在素材与数据文件夹下。

6、数据访问方式不作限制,可以使用任意ORM框架或数据库访问组件,如JDB、MyBatis、Hibernate、LINQ to SQL/Entity、Entity Framework、ADO.NET等。

普通:

分页

后台添加

模块块、Maven、Git

高级:

在普通的基础上增加多字段排序(可以选择排序类型与升降序)

CRUD

 素材下载:https://git.dev.tencent.com/zhangguo5/MyBatis06.git