1 逆向工程的简介

Mybatis 的逆向工程就是由代码生成器生成我们需要的代码和映射文件。

注意,逆向工程时最好新开一个项目,否则可能出现相同文件名覆盖的情况。

官方文档:MyBatis Generator Core – Introduction to MyBatis Generator

2 逆向工程代码

2.1 导入 Maven 依赖和插件

<dependencies>
	<!-- MyBatis核心依赖包 -->
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis</artifactId>
		<version>3.5.9</version>
	</dependency>
	<!-- junit测试 -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>4.13.2</version>
		<scope>test</scope>
	</dependency>
	<!-- MySQL驱动 -->
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<version>8.0.27</version>
	</dependency>
	<!-- log4j日志 -->
	<dependency>
		<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.17</version>
	</dependency>
</dependencies>
<!-- 控制Maven在构建过程中相关配置 -->
<build>
	<!-- 构建过程中用到的插件 -->
	<plugins>
		<!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
		<plugin>
			<groupId>org.mybatis.generator</groupId>
			<artifactId>mybatis-generator-maven-plugin</artifactId>
			<version>1.3.0</version>
			<!-- 插件的依赖 -->
			<dependencies>
				<!-- 逆向工程的核心依赖 -->
				<dependency>
					<groupId>org.mybatis.generator</groupId>
					<artifactId>mybatis-generator-core</artifactId>
					<version>1.3.2</version>
				</dependency>
				<!-- 数据库连接池 -->
				<dependency>
					<groupId>com.mchange</groupId>
					<artifactId>c3p0</artifactId>
					<version>0.9.2</version>
				</dependency>
				<!-- MySQL驱动 -->
				<dependency>
					<groupId>mysql</groupId>
					<artifactId>mysql-connector-java</artifactId>
					<version>8.0.27</version>
				</dependency>
			</dependencies>
		</plugin>
	</plugins>
</build>

2.2 导入 log4j 配置

略。

2.3 创建 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">
<configuration>
    <properties resource="jdbc.properties"/>
    <typeAliases>
        <package name=""/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name=""/>
    </mappers>
</configuration>

2.4 创建 generatorConfig.xml 配置文件

<?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>
    <!--
    targetRuntime: 执行生成的逆向工程的版本
    MyBatis3Simple: 生成基本的 CRUD(清新简洁版)
    MyBatis3: 生成带条件的 CRUD(奢华尊享版)
    -->
    <context id="testTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <!-- 是否去除自动生成的注释。true:是;false:否 -->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&amp;useUnicode=true&amp;characterEncoding=utf-8"
                        userId="root"
                        password="root">
        </jdbcConnection>
 
        <!-- 默认false,把JDBC DECIMAL和NUMERIC类型解析为Integer,为true时把JDBC DECIMAL 和
            NUMERIC 类型解析为java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false" />
        </javaTypeResolver>
 
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="com.thr.pojo"
                            targetProject="./src/main/java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.thr.mapper"
                         targetProject="./src/main/resources">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.thr.mapper"
                             targetProject="./src/main/java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_emp" domainObjectName="Emp"/>
        <table tableName="t_dept" domainObjectName="Dept"/>
        <!-- 指定生成哪些数据库表,要和数据库中对应,不能写错了,这里以t_user表为例,可以写多个;domainObjectName是要生成的实体类名称-->
        <table schema="mybatis" tableName="t_user"/>
        <!-- 有些表的字段需要指定java类型
         <table schema="" tableName="">
            <columnOverride column="" javaType="" />
        </table> -->
    </context>
</generatorConfiguration>

还有就是不同的数据库中不能含有相同的表,例如数据库 A 有 t_user 表,数据库 B 也有 t_user 表,那么到时候代码不知道生成哪个。

2.5 执行逆向——编码形式

逆向工程核心生成代码 GeneratorSql.java

package com.thr.generator;
 
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;
 
import java.io.File;
import java.util.ArrayList;
import java.util.List;
 
public class GeneratorSql {
    public void generator() throws Exception {
        List<String> warnings = new ArrayList<>();
        boolean overwrite = true;
        // 指定逆向工程配置文件
        String file = GeneratorSql.class.getResource("/generatorConfig.xml").getFile();
        File configFile = new File(file);
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
    }
    // 执行main方法以生成代码
    public static void main(String[] args) {
        try {
            GeneratorSql generatorSql = new GeneratorSql();
            generatorSql.generator();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
}

运行上面的程序,如果控制台打印了如下日志,说明生成代码成功了。

image

2.6 执行逆向——插件

执行结果

3 逆向工程举例

首先我们将上面生成的文件复制到目标项目中。在使用逆向工程举例之前,先来介绍生成的文件有哪些东西:

3.1 TUserMapper 接口生成的方法介绍

  1. long countByExample(TUserExample example) :按条件计数
  2. int deleteByExample(TUserExample example) :按条件删除
  3. int deleteByPrimaryKey(Integer id) :按主键删除
  4. int insert(TUser record) :插入数据(返回值为 ID),包含值为 null 的字段
  5. int insertSelective(TUser record) :插入数据,只插入值不为 null 的字段,内部动态 sql 判断
  6. List<TUser> selectByExample(TUserExample example) :按条件查询,传入 null 表示查询所有
  7. TUser selectByPrimaryKey(Integer id) :按主键查询
  8. int updateByExampleSelective(@Param("record") TUser record, @Param("example") TUserExample example) :按条件更新值不为 null 的字段
  9. int updateByExample(@Param("record") TUser record, @Param("example") TUserExample example) :按条件更新
  10. int updateByPrimaryKeySelective(TUser record) :按主键更新值不为 null 的字段,主键对应实体类属性不能为 null。
  11. int updateByPrimaryKey(TUser record) :按主键更新

代码示例

List<TUser> tUsers = mapper.selectByExample(null);//传入null表示查询所有

3.2 TUserExample 条件扩展类介绍

上面的测试方法是不带条件的操作,那么接下来学习一下按条件如何进行增删改查操作,我们在逆向工程中已经生成了这个类 TUserExample,这个类就是一个条件扩展类,里面定义了一系列方法用来做条件,比如:排序、去重、大于、小于、等于、模糊查询、数据在某某之间等等。

我们在 TUserExample 类中可以看到定义了一个内部类 GeneratedCriteria,这个内部类就定义了一系列条件的方法,这些条件最后都会拼接在 SQL 中,但是我们一般不用它,都用它的子类 Criteria 来进行操作,Criteria 继承了内部类 GeneratedCriteria。

需要学习的内容:

  1. criteria 是可以链式添加条件的
    criteria.andUsernameLike("%三%").andAgeBetween(18,30);
  2. or 操作的使用
    example.or(criteria1)
    example.or(criteria2)
    example.or(criteria3)
    其中 criteria1、criteria2、criteria3 分别代表一个链式的判断条件

代码示例

//模糊查询用户信息
@Test
public void selectUserLike(){
	TUserExample example = new TUserExample();
	TUserExample.Criteria criteria = example.createCriteria();
	//模糊条件
	criteria.andUsernameLike("%三%");
	/*sql语句相当于:select id, username, age, birthday, sex, address from t_user WHERE ( username like ? )*/
	List<TUser> tUsers = mapper.selectByExample(example);
}
 
 
//查询年龄在18-30岁之间的用户信息
@Test
public void selectUserBetween(){
	TUserExample example = new TUserExample();
	TUserExample.Criteria criteria = example.createCriteria();
	//Between条件
	criteria.andAgeBetween(18,30);
	example.or(criteria);
	example.setDistinct(true);
	/*sql语句相当于:select distinct id, username, age, birthday, sex, address
					from t_user WHERE ( age between ? and ? ) or( age between ? and ? )*/
	List<TUser> tUsers = mapper.selectByExample(example);
	for (TUser tUser : tUsers) {
		System.out.println(tUser);
	}
}
 
 
//查询用户名A或B
@Test
public void selectUserOr(){
	TUserExample example = new TUserExample();
	TUserExample.Criteria criteria1 = example.createCriteria();
	criteria1.andUsernameEqualTo("黄飞鸿");
 
	TUserExample.Criteria criteria2 = example.createCriteria();
	criteria2.andUsernameEqualTo("马保国");
	//将criteria2条件拼接在 or 关键字字后面
	example.or(criteria2);
	/*sql语句相当于:select id, username, age, birthday, sex, address
		from t_user WHERE ( username = ? ) or( username = ? )*/
	List<TUser> tUsers = mapper.selectByExample(example);
	for (TUser tUser : tUsers) {
		System.out.println(tUser);
	}
}
 
 
//根据用户名删除用户
@Test
public void deleteUserExample(){
	TUserExample example = new TUserExample();
	TUserExample.Criteria criteria = example.createCriteria();
	criteria.andUsernameEqualTo("凡尔赛");
	//sql语句相当于:delete from t_user WHERE ( username = ? )
	int i = mapper.deleteByExample(example);
	System.out.println(i>0?"删除成功":"删除失败");
}

4 树