1、什么是逆向工程
Mybatis的逆向工程就是由代码生成器生成我们需要的代码和映射文件。我们在编写Mybatis程序时,基本都是围绕着pojo类,Mapper接口,Mapper.xml文件等文件来进行的。如果实际开发中数据库的表特别多,那么我们需要手动去写每一张表的pojo类,Mapper接口,Mapper.xml文件,这显然需要花费巨大的精力,而且可能由于表字段太多,哪里写错了都难以排除。所以我们在实际开发中,一般使用逆向工程方式来自动生成所需的文件,这也是企业中一种非常常见的方法。
注意:在使用逆向工程生成代码文件的时候,最好额外创建一个项目,不要在原来的项目中使用,因为如果你在原项目中有相同名字的文件,那么就会被新生成的文件所覆盖,导致之前写的代码没了,有一定的风险。所以实际开发中,我们一般新建一个项目,然后将生成的文件复制到自己的所需的工程中。
2、逆向工程生成代码
①、首先创建maven项目
项目整体目录:
导入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
③、创建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表为例,可以写多个 --> <table schema="mybatis" tableName="t_user"/> <!-- 有些表的字段需要指定java类型 <table schema="" tableName=""> <columnOverride column="" javaType="" /> </table> --> </context> </generatorConfiguration>
注意:serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8中的 & 要改成转义字符 & 这里传上来页面自动给转成了 &。
还有就是不同的数据库中不能含有相同的表,例如数据库A有t_user表,数据库B也有t_user表,那么到时候代码不知道生成哪个,而我恰好生成的是我们不需要的那个。啊?你说上面不是指定了数据库吗,怎么会到读取到其它数据库的表,不好意思,我试了不下十遍,最后我把其它数据库同名的表删除才成功的。如果你没有这种情况那更好咯。
④、创建逆向工程核心生成代码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(); } } }
⑤、运行逆向工程核心生成代码
运行上面的程序,如果控制台打印了如下日志,说明生成代码成功了。
然后我们再看项目就会发现生成了如下文件:
下面我们就来学习如何使用它们。
3、逆向工程举例
首先我们将上面生成的文件复制到目标项目中。在使用逆向工程举例之前,先来介绍生成的文件有哪些东西:
(1)、TUserMapper接口生成的方法介绍:
- long countByExample(TUserExample example):按条件计数
- int deleteByExample(TUserExample example):按条件删除
- int deleteByPrimaryKey(Integer id):按主键删除
- int insert(TUser record):插入数据(返回值为ID)
- int insertSelective(TUser record):插入数据,只插入值不为null的字段,内部动态sql判断
- List<TUser> selectByExample(TUserExample example):按条件查询,传入null表示查询所有
- TUser selectByPrimaryKey(Integer id):按主键查询
- int updateByExampleSelective(@Param("record") TUser record, @Param("example") TUserExample example):按条件更新值不为null的字段
- int updateByExample(@Param("record") TUser record, @Param("example") TUserExample example):按条件更新
- int updateByPrimaryKeySelective(TUser record):按主键更新值不为null的字段
- 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。
简单举例:
//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类,但如果自己多举几个例子也不难。