Hey, Nice to meet You. 

必有过人之节.人情有所不能忍者,匹夫见辱,拔剑而起,挺身而斗,此不足为勇也,天下有大勇者,猝然临之而不惊,无故加之而不怒.此其所挟持者甚大,而其志甚远也.          ☆☆☆所谓豪杰之士,

Mybatis3详解(十三)----Mybatis逆向工程

1、什么是逆向工程

Mybatis的逆向工程就是由代码生成器生成我们需要的代码和映射文件。我们在编写Mybatis程序时,基本都是围绕着pojo类,Mapper接口,Mapper.xml文件等文件来进行的。如果实际开发中数据库的表特别多,那么我们需要手动去写每一张表的pojo类,Mapper接口,Mapper.xml文件,这显然需要花费巨大的精力,而且可能由于表字段太多,哪里写错了都难以排除。所以我们在实际开发中,一般使用逆向工程方式来自动生成所需的文件,这也是企业中一种非常常见的方法。

注意:在使用逆向工程生成代码文件的时候,最好额外创建一个项目,不要在原来的项目中使用,因为如果你在原项目中有相同名字的文件,那么就会被新生成的文件所覆盖,导致之前写的代码没了,有一定的风险。所以实际开发中,我们一般新建一个项目,然后将生成的文件复制到自己的所需的工程中。

2、逆向工程生成代码

①、首先创建maven项目

项目整体目录:

image

导入maven依赖:

    <!-- Mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    <!-- mysql驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
    <!-- 日志处理 -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <!-- 逆向工程 -->
    <dependency>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-core</artifactId>
        <version>1.4.0</version>
    </dependency>

②、创建日志文件log4j.properties

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

③、创建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"表示生成简易版本,这里创建原始版本,参数为MyBatis3-->
    <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&useUnicode=true&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>

        <!-- targetProject:POJO类生成的位置 -->
        <javaModelGenerator targetPackage="com.thr.pojo"
                            targetProject="./src/main/java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
            <!-- 从数据库返回的值被清理前后的空格 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- targetProject:mapper映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="com.thr.mapper"
                         targetProject="./src/main/resources">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- targetPackage:mapper接口生成的位置 -->
        <javaClientGenerator type="XMLMAPPER"
                             targetPackage="com.thr.mapper"
                             targetProject="./src/main/java">
            <!-- enableSubPackages:是否让schema作为包的后缀 -->
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- 指定生成哪些数据库表,要和数据库中对应,不能写错了,这里以t_user表为例,可以写多个;domainObjectName是要生成的实体类名称-->
        <table schema="mybatis" tableName="t_user"/>

        <!-- 有些表的字段需要指定java类型
         <table schema="" tableName="">
            <columnOverride column="" javaType="" />
        </table> -->
    </context>
</generatorConfiguration>

注意:serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8中的 & 要改成转义字符 &amp; 这里传上来页面自动给转成了 &。

image

还有就是不同的数据库中不能含有相同的表,例如数据库A有t_user表,数据库B也有t_user表,那么到时候代码不知道生成哪个,而我恰好生成的是我们不需要的那个。啊?你说上面不是指定了数据库吗,怎么会到读取到其它数据库的表,不好意思,我试了不下十遍,最后我把其它数据库同名的表删除才成功的。如果你没有这种情况那更好咯。

脑壳痛 (1)

 

④、创建逆向工程核心生成代码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

然后我们再看项目就会发现生成了如下文件:

image

下面我们就来学习如何使用它们。

3、逆向工程举例

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

(1)、TUserMapper接口生成的方法介绍:

  1. long countByExample(TUserExample example):按条件计数
  2. int deleteByExample(TUserExample example):按条件删除
  3. int deleteByPrimaryKey(Integer id):按主键删除
  4. int insert(TUser record):插入数据(返回值为ID)
  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的字段
  11. int updateByPrimaryKey(TUser record):按主键更新

测试不带条件的方法:

//Mybatis的测试
public class MybatisTest {
    //定义 SqlSession
    private SqlSession sqlSession = null;
    //定义 TUserMapper对象
    private TUserMapper mapper = null;

    @Before//在测试方法执行之前执行
    public void getSqlSession(){
        //1、加载 mybatis 全局配置文件
        InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        //2、创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //3、根据 sqlSessionFactory 产生session
        sqlSession = sqlSessionFactory.openSession();
        //4、创建Mapper接口的的代理对象,getMapper方法底层会通过动态代理生成TUserMapper的代理实现类
        mapper = sqlSession.getMapper(TUserMapper.class);
    }

    @After//在测试方法执行完成之后执行
    public void destroy() throws IOException {
        sqlSession.commit();
        sqlSession.close();
    }
    //查询所有用户信息
    @Test
    public void selectAllUser(){
        List<TUser> tUsers = mapper.selectByExample(null);//传入null表示查询所有
        for (TUser tUser : tUsers) {
            System.out.println(tUser);
        }
    }
    //根据用户id查询用户
    @Test
    public void selectByUserId(){
        TUser tUser = mapper.selectByPrimaryKey(1);
        System.out.println(tUser);
    }
    //添加用户信息
    @Test
    public void insertUser(){
        TUser tUser = new TUser();
        tUser.setUsername("凡尔赛");
        tUser.setAge(18);
        tUser.setBirthday(new Date());
        tUser.setSex("0");
        tUser.setAddress("漂亮国");
        int i = mapper.insertSelective(tUser);
        System.out.println(i>0?"添加成功":"添加失败");
    }
    //更新用户信息
    @Test
    public void updateUser(){
        TUser tUser = new TUser();
        tUser.setId(8);//这里要设置id才能修改成功,否则不知道修改哪一条数据
        tUser.setUsername("川建国");
        tUser.setAge(50);
        tUser.setBirthday(new Date());
        tUser.setSex("1");
        tUser.setAddress("漂亮国");
        int i = mapper.updateByPrimaryKeySelective(tUser);
        System.out.println(i>0?"修改成功":"修改失败");
    }
    //删除用户信息
    @Test
    public void deleteUser(){
        int i = mapper.deleteByPrimaryKey(8);
        System.out.println(i>0?"删除成功":"删除失败");
    }
}

(2)、TUserExample条件扩展类介绍:

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

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

image

简单举例:

//Mybatis的测试
public class MybatisTest1 {
    //定义 SqlSession
    private SqlSession sqlSession = null;
    //定义 UserMapper对象
    private TUserMapper mapper = null;

    @Before//在测试方法执行之前执行
    public void getSqlSession(){
        //1、加载 mybatis 全局配置文件
        InputStream is = MybatisTest1.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        //2、创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //3、根据 sqlSessionFactory 产生session
        sqlSession = sqlSessionFactory.openSession();
        //4、创建Mapper接口的的代理对象,getMapper方法底层会通过动态代理生成UserMapper的代理实现类
        mapper = sqlSession.getMapper(TUserMapper.class);
    }

    @After//在测试方法执行完成之后执行
    public void destroy() throws IOException {
        sqlSession.commit();
        sqlSession.close();
    }
    //模糊查询用户信息
    @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);
        for (TUser tUser : tUsers) {
            System.out.println(tUser);
        }
    }
    //查询年龄在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?"删除成功":"删除失败");
    }
}

至此Mybatis的逆向工程就全部介绍完成了,说难也不是特别难,只要一步步自己去实现,去理解一遍,是非常简单的,可能复杂一点的是那个XxxExample类,但如果自己多举几个例子也不难。    

posted @ 2020-11-21 20:22  唐浩荣  阅读(4243)  评论(1编辑  收藏  举报