绝对详细的MyBatis代码生成器讲解

0.简介

在springboot工程中如果使用mybatis作为持久层框架,那必须知道如何自动生成 java 实体类、dao 层接口(mapper 接口)及mapper.xml文件,这样可以减少不必要的开发。

生成代码的方式有很多种,比如说利用idea的插件、maven插件,使用代码执行方法去生成

下面分享一下利用代码去生成我们需要的实体类、dao、mapper.xml

1.快速开始

打开官网:http://mybatis.org/generator/quickstart.html,官网里面描述的已经很清楚了,下面我们重新解释一下它的配置,这是重点,整个代码的核心就是这个配置

DOCTYPE generatorConfiguration PUBLIC
 "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
 "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
  <context id="simple" targetRuntime="MyBatis3">
    <jdbcConnection driverClass="org.hsqldb.jdbcDriver"
        connectionURL="jdbc:hsqldb:mem:aname" />

    <javaModelGenerator targetPackage="example.model" targetProject="src/main/java"/>

    <sqlMapGenerator targetPackage="example.mapper" targetProject="src/main/resources"/>

    <javaClientGenerator type="XMLMAPPER" targetPackage="example.mapper" targetProject="src/main/java"/>

    <table tableName="FooTable" />
  context>
generatorConfiguration>

这是官网给出的一段简单的配置,我们一般会在resources目录下新建一个mybatisGeneratorConfig.xml这样的配置文件。这个配置里面有几个重要的标签,下面我们就解读一下这份配置

2.根节点 generatorConfiguration

它主要是包含三个子元素

属性 描述
properties 引入配置资源,例如数据库配置信息
classPathEntry 引入类路径,例如引入JDBC的驱动程序
context 用于指定生成一组对象的环境

这些子元素的顺序最好按照表格的顺序来配置,properties放在最前面,context放在最后面

3.引入配置properties

这个元素不是必须的,它有两个属性

属性 描述
resource 相对资源
url 全路径

一般情况下我们的mybatisGeneratorConfig.xml配置文件和application.properties项目配置文件都是在resources目录下,因此使用resource属性,可以以下方式:

<properties resource="application.properties"/>

如果使用url,则

<properties url="file:///F:\javaStudy\mybatis-generator\mybatisGenerator\src\main\resources\application.properties"/>

一般情况下我们都是使用resource这个属性,如果使用url,不同开发人员项目所在的目录一般都是不一样的,比如我的项目是放在本机上的F盘,而有些人是E盘

4.JDBC驱动classPathEntry

这个元素用于引入某些类的路径,例如JDBC驱动类

属性 描述
location 相对路径或绝对路径

配置如下

<classPathEntry location="E:/apache-maven-3.8.5/repository/mysql/mysql-connector-java/8.0.18/mysql-connector-java-8.0.18.jar"/>

classPathEntry只在下面这两种情况下才有效

  1. 当加载 JDBC 驱动内省数据库时
  2. 当加载根类中的 JavaModelGenerator 检查重写的方法时

5.context

元素用于指定生成一组对象的环境 ,有以下四个属性

属性 描述
id context唯一标识,用于追踪错误信息
defaultModelType 如果目标运行时为“MyBatis3Simple”、“MyBatis 3DynamicSql”或“MyBatist3Kotlin”,则忽略此属性,它有下面三个值conditional(默认),flat(推荐),hierarchical
targetRuntime 此属性用于指定生成的代码的运行时环境,有四个可选值:MyBatis3DynamicSql 、 MyBatis3Kotlin 、 MyBatis3(默认) 、 MyBatis3Simple
introspectedColumnImpl 该参数可以指定扩展org.mybatis.generator.api.IntrospectedColumn该类的实现类

它有以下几个子元素

  1. property
  2. plugin
  3. commentGenerator
  4. connectionFactory
  5. jdbcConnection
  6. javaTypeResolver
  7. javaModelGenerator
  8. sqlMapGenerator
  9. javaClientGenerator
  10. table

这些元素需要按照严格的顺序来,后面会对属性逐一讲解

context配置例子

<context id="mysql_tables" targetRuntime="MyBatis3" defaultModelType="flat">
    //子元素配置项
context>  

使用MyBatis3 生成的mapper内容

long countByExample(StudentExample example);

int insert(Student row);

int insertSelective(Student row);

List<Student> selectByExample(StudentExample example);

Student selectByPrimaryKey(Long id);

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

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

int updateByPrimaryKeySelective(Student row);

int updateByPrimaryKey(Student row);

而使用MyBatis3Simple生成的mapper如下

int insert(Student row);

Student selectByPrimaryKey(Long id);

List<Student> selectAll();

int updateByPrimaryKey(Student row);

很显然MyBatis3要比MyBatis3Simple生成的方法要多,正常情况下我们使用MyBatis3会比较多

5.1property

它有以下几个属性

属性 描述
autoDelimitKeywords 如果为true,则如果SQL关键字用作表中的列名,则MBG将对其进行分隔,默认值是false
beginningDelimiter 要用作需要分隔符的SQL标识符的起始标识符分隔符的值,默认值为双引号(“)
endingDelimiter 要用作需要分隔符的SQL标识符的结束标识符分隔符的值,默认值为双引号(“)
javaFileEncoding java文件的编码
javaFormatter 使用此属性可以为生成的Java文件指定用户提供的格式化程序的完整类名
kotlinFileEncoding Kotlin文件的编码
kotlinFormatter 使用此属性可以为生成的Kotlin文件指定用户提供的格式化程序的完整类名
xmlFormatter 使用此属性可以为生成的XML文件指定用户提供的格式化程序的完整类名

配置例子:

<context id="mysql_tables" targetRuntime="MyBatis3" defaultModelType="flat">
    <property name="beginningDelimiter" value=""/>
    <property name="endingDelimiter" value=""/>
    <property name="javaFileEncode" value="UTF-8"/>
context>  

5.2plugin

元素用于定义插件,它有一个属性

属性 描述
type 完整的类名

配置例子


<plugin type="org.mybatis.generator.plugins.SerializablePlugin" />

<plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin">
    <property name="useEqualsHashCodeFromRoot" value="true"/>
plugin>

<plugin type="org.mybatis.generator.plugins.ToStringPlugin">
    <property name="useToStringFromRoot" value="true"/>
plugin>

<plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />

生成的实体类会包含下面的几个方法

@Override
public boolean equals(Object that) {
    // 代码省略
}

@Override
public int hashCode() {
   // 代码省略
}

@Override
public String toString() {
    // 代码省略
}

5.3注释commentGenerator

该元素主要用于配置注释,它有一个属性

属性 描述
type 完整的类名

它有一个子元素property,主要包含以下几个属性

属性 描述
suppressAllComments 不让生成注释,默认值是false,表示生成注释,如果为true,表示不让生成注释
suppressDate 不让生成的注释包含时间戳,默认值是false
addRemarkComments 添加 db 表中字段的注释
dateFormat 将日期写入生成的注释时使用的日期格式字符串
useLegacyGeneratedAnnotation 指定是否使用不推荐使用的“javax”命名空间中的注释

比较常用的是suppressAllCommentssuppressDateaddRemarkComments

配置例子

 
<commentGenerator type="com.example.mybatisgenerator.CommentGenerator">
    
    <property name="addRemarkComments" value="true"/>
    
    <property name="suppressAllComments" value="true"/>
    
    <property name="suppressDate" value="true"/>
commentGenerator>

不知道大家有没有注意到com.example.mybatisgenerator.CommentGenerator是我自定义的注释实现类,这里为什么要自定义呢?

	/**
     * Database Column Remarks:
     *   自增ID
     *
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column student.id
     *
     * @mbg.generated
     */
    private Long id;

    /**
     * Database Column Remarks:
     *   名称
     *
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database column student.name
     *
     * @mbg.generated
     */
    private String name;

这是mybatis自带的注释格式,为了简洁一些,一般都会自定义一个注释的实现类

package com.example.mybatisgenerator;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;
import java.util.Properties;

public class CommentGenerator extends DefaultCommentGenerator {
    private boolean addRemarkComments = false;

    @Override
    public void addConfigurationProperties(Properties props){
        super.addConfigurationProperties(props);
        this.addRemarkComments = StringUtility.isTrue(props.getProperty("addRemarkComments"));
    }

    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable,
                                IntrospectedColumn introspectedColumn) {
        String remarks = introspectedColumn.getRemarks();
        if (addRemarkComments && StringUtility.stringHasValue(remarks)){
            field.addJavaDocLine("/**");
            String[] remarkLines = remarks.split(System.getProperty("line.separator"));
            for (String remarkLine : remarkLines) {
                field.addJavaDocLine(" * " + remarkLine);
            }
            field.addJavaDocLine(" */");
        }
    }
}

最后生成这样的注释

	/**
     * 自增ID
     */
    private Long id;

    /**
     * 名称
     */
    private String name;

    /**
     * 年龄
     */
    private Integer age;

5.4数据库jdbcConnection

元素用于指定内省表所需的数据库连接的属性

属性 描述
driverClass 用于访问数据库的JDBC驱动程序的完全限定类名
connectionURL 用于访问数据库的JDBC连接URL
userId 数据库账号
password 数据库密码

配置例子:


<jdbcConnection
                driverClass="${spring.datasource.driver-class-name}"
                connectionURL="${spring.datasource.url}"
                userId="${spring.datasource.username}"
                password="${spring.datasource.password}">
jdbcConnection>

前面介绍了properties元素,主要是引入一些外部配置,我们可以通过${}的方式去访问变量

5.5解析类型javaTypeResolver

元素用于定义Java类型解析程序的属性,它有一个属性

属性 描述
type Java类型解析程序

它有一个子元素property,主要包含以下几个属性

属性 描述
forceBigDecimals 强制转换DECIMAL和NUMERIC字段为java.math.BigDecimal
useJSR310Types 强制使用DATE、TIME和TIMESTAMP字段的JSR-310数据类型,而不是使用java.util.DATE

配置例子

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

5.6实体类javaModelGenerator

这个是生成实体类配置标签,它有两个必选属性

属性 描述
targetPackage 生成实体类存放的包路径
targetProject 指定目标项目路径,可以是绝对路径或相对路径

它还包含了下面几个 property 子元素属性

属性 描述
constructorBased :该属性只对MyBatis3有效,如果true就会使用构造方法入参,如果false就会使用setter方式。默认为false
enableSubPackages 如果true,MBG会根据catalogschema来生成子包,默认是false
immutable 用来配置实体类属性是否可变,默认是false
rootClass 设置所有实体类的基类
trimStrings 是否去掉返回数据的空白符

加粗的属性enableSubPackagestrimStrings是比较常用的配置

配置示例如下:

 
<javaModelGenerator  targetPackage="com.example.mybatisgenerator.entity"
                    targetProject="src\main\java">
    <property name="enableSubPackages" value="true" />
    <property name="trimStrings" value="true"/>
javaModelGenerator>

绝对详细的MyBatis代码生成器讲解_第1张图片

5.7SQL映射sqlMapGenerator

元素用于定义SQL映射生成器的属性,它有两个必选属性

属性 描述
targetPackage xml存放的包路径
targetProject 指定目标项目路径,可以是绝对路径或相对路径

property 子元素属性

属性 描述
enableSubPackages 如果true,MBG会根据catalogschema来生成子包,默认是false

配置例子


<sqlMapGenerator
                 targetPackage="mapper"
                 targetProject="src\main\resources">
    <property name="enableSubPackages" value="true" />
sqlMapGenerator>

绝对详细的MyBatis代码生成器讲解_第2张图片

5.8持久层javaClientGenerator

元素用于定义Java客户端生成器的属性,其实就说持久层(DAO)接口,它包含三个属性

属性 描述
type 此属性用于选择预定义的Java客户端生成器之一,或指定用户提供的Java客户端生成程序
targetPackage 生成实体类存放的包路径
targetProject 指定目标项目路径,可以是绝对路径或相对路径

property 子元素属性

属性 描述
enableSubPackages 如果true,MBG会根据catalogschema来生成子包,默认是false
dynamicSqlSupportPackage 此属性仅适用于目标运行时MyBatis3DynamicSql或MyBatis3Kotlin

配置例子


<javaClientGenerator type="XMLMAPPER"
                     targetPackage="com.example.mybatisgenerator.mapper"
                     targetProject="src\main\java">
    <property name="enableSubPackages" value="true" />
javaClientGenerator>

绝对详细的MyBatis代码生成器讲解_第3张图片

5.9数据表table

元素用于为每个表生成实体类、sql映射文件(xml),持久层接口(DAO),这是非常重要的配置

属性 描述
tableName 必填属性,数据库表,如果需要,指定的值可以包含SQL通配符
schema 数据库模式-如果数据库不使用模式,或者有默认模式,则不需要数据库模式。如果需要,指定的值可以包含SQL通配符。
catalog 数据库目录-如果数据库不使用目录,或者有默认目录,则不需要该目录
alias 别名,例如 select * from news as n,会为表加上别名。 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
domainObjectName 实体类名称。比如表名是news,会生成News、NewsMapper等文件,如果设置该属性为NewsPO,那么会生成NewsPO、NewsPOMapper
mapperName Mapper的名称 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
sqlProviderName sql映射文件(xml)的名称 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
enableInsert 插入方法,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
enableSelectByPrimaryKey 根据主键查询方法 ,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
enableSelectByExample 根据条件查询方法 ,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
enableUpdateByPrimaryKey 根据主键更新方法,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
enableDeleteByPrimaryKey 根据主键删除方法,一般情况下都是软删除,因此一般不生成该方法 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
enableDeleteByExample 根据条件删除方法,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
enableCountByExample 根据条件查询总数方法,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
enableUpdateByExample 根据条件更新方法,默认值为true 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
selectByPrimaryKeyQueryId 此值将以以下形式添加到select by主键语句的select列表中:“''as QUERYID”。这对于在运行时识别DBA跟踪工具中的查询非常有用。如果您使用这样的值,您应该为MBG生成的每个不同的查询指定一个唯一的id。 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
selectByExampleQueryId 此值将以以下形式添加到select by example语句的select列表中:“''as QUERYID”。这对于在运行时识别DBA跟踪工具中的查询非常有用。如果您使用这样的值,您应该为MBG生成的每个不同的查询指定一个唯一的id 注意目标运行时为“MyBatis3DynamicSql”或“MyBatis 3Kotlin”,则忽略此属性
modelType 如果希望为此表覆盖默认模型类型,则使用此属性
escapeWildcards 指示在搜索列时是否应转义架构和tableName中的SQL通配符(“_”和“%”)。如果架构或表名包含SQL通配符,则某些驱动程序需要这样做(例如,如果表名为MY_table,则某些驱动器要求转义下划线).默认值为false。
delimitIdentifiers 指示MBG在搜索表时是否应使用指定的大小写,然后在生成的SQL中对标识符进行定界。默认值为false
delimitAllColumns 指示MBG是否应向生成的SQL中的所有列名添加分隔符。默认值为false

它有下面几个属性

  1. property
  2. generatedKey
  3. domainObjectRenamingRule
  4. columnRenamingRule
  5. columnOverride
  6. ignoreColumn

下面对generatedKey和columnOverride进行讲解

generatedKey

主键生成属性,默认情况下都是都是这样配置

<generatedKey column="id" sqlStatement="Mysql" identity="false" />

columnOverride

重新某些字段的值,这个比较有用,比如说数据表的TINYINT型字段默认对应的javaType是Byte,有时候我们需要转成Integer


下面是一个table的配置示例


        <table tableName="student"
               enableCountByExample="true"
               enableUpdateByExample="true"
               enableDeleteByExample="false"
               enableSelectByExample="true"
               selectByExampleQueryId="true"
               enableSelectByPrimaryKey="true"
               enableUpdateByPrimaryKey="true"
               enableDeleteByPrimaryKey="false"
        >
            <generatedKey column="id" sqlStatement="Mysql" identity="false" />
            <columnOverride column="deleted" javaType="Integer" jdbcType="TINYINT"/>
            <columnOverride column="create_time" javaType="java.time.LocalDateTime" jdbcType="TIMESTAMP"/>
            <columnOverride column="update_time" javaType="java.time.LocalDateTime" jdbcType="TIMESTAMP"/>
        table>

6.实践

1.引入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>8.0.28version>
    dependency>
    
    <dependency>
        <groupId>com.zaxxergroupId>
        <artifactId>HikariCPartifactId>
    dependency>
    
    <dependency>
        <groupId>org.mybatis.spring.bootgroupId>
        <artifactId>mybatis-spring-boot-starterartifactId>
        <version>2.2.0version>
    dependency>
    
    <dependency>
        <groupId>org.mybatis.generatorgroupId>
        <artifactId>mybatis-generator-coreartifactId>
        <version>1.4.1version>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>
dependencies>

2.配置

spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

3.mybatis生成器xml配置


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="application.properties"/>

    <classPathEntry location="E:/apache-maven-3.8.5/repository/mysql/mysql-connector-java/8.0.18/mysql-connector-java-8.0.18.jar"/>

    
    <context id="mysql_tables" targetRuntime="MyBatis3" defaultModelType="flat">
        <property name="beginningDelimiter" value=""/>
        <property name="endingDelimiter" value=""/>
        <property name="javaFileEncode" value="UTF-8"/>

        
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
        
        <plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin">
            <property name="useEqualsHashCodeFromRoot" value="true"/>
        plugin>
        
        <plugin type="org.mybatis.generator.plugins.ToStringPlugin">
            <property name="useToStringFromRoot" value="true"/>
        plugin>
        
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />

        
        <commentGenerator type="com.example.mybatisgenerator.CommentGenerator">
            
            <property name="addRemarkComments" value="true"/>
            
            <property name="suppressAllComments" value="true"/>
            
            <property name="suppressDate" value="true"/>
        commentGenerator>

        
        <jdbcConnection
                driverClass="${spring.datasource.driver-class-name}"
                connectionURL="${spring.datasource.url}"
                userId="${spring.datasource.username}"
                password="${spring.datasource.password}">
        jdbcConnection>

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

        
        <javaModelGenerator  targetPackage="com.example.mybatisgenerator.entity"
                             targetProject="src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true"/>
        javaModelGenerator>

        
        <sqlMapGenerator
                targetPackage="mapper"
                targetProject="src\main\resources">
            <property name="enableSubPackages" value="true" />
        sqlMapGenerator>

        
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.example.mybatisgenerator.mapper"
                             targetProject="src\main\java">
            <property name="enableSubPackages" value="true" />
        javaClientGenerator>

        
        <table tableName="student"
               enableCountByExample="true"
               enableUpdateByExample="true"
               enableDeleteByExample="false"
               enableSelectByExample="true"
               selectByExampleQueryId="true"
               enableSelectByPrimaryKey="true"
               enableUpdateByPrimaryKey="true"
               enableDeleteByPrimaryKey="false"
        >
            <generatedKey column="id" sqlStatement="Mysql" identity="false" />
            <columnOverride column="deleted" javaType="Integer" jdbcType="TINYINT"/>
            <columnOverride column="create_time" javaType="java.time.LocalDateTime" jdbcType="TIMESTAMP"/>
            <columnOverride column="update_time" javaType="java.time.LocalDateTime" jdbcType="TIMESTAMP"/>
        table>

    context>
generatorConfiguration>

com.example.mybatisgenerator.CommentGenerator自定义注释的实现类代码上面有

4.启动

在测试类里面写一个方法

@Test
void generate() throws XMLParserException, IOException, InvalidConfigurationException, SQLException, InterruptedException {
    List<String> warnings = new ArrayList<>();
    InputStream in = MyBatisGenerator.class.getClassLoader().getResourceAsStream("mybatisGeneratorConfig.xml");
    ConfigurationParser cp = new ConfigurationParser(warnings);
    Configuration config = cp.parseConfiguration(in);
    assert in != null;
    in.close();

    // 覆盖 Java 文件
    boolean overwrite = true;
    DefaultShellCallback callback = new DefaultShellCallback(overwrite);
    MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);

    // 生成文件
    myBatisGenerator.generate(null);
    // 打印信息
    warnings.forEach(System.err::println);
}

你可能感兴趣的:(mybatis)