文章目录
1、MyBatis逆向工程综述
在之前的工程中,实现一个查询功能,首先要根据数据库中的相关表创建响应的Java实体类,然后还需要配置一个SQL映射文件,如果使用Mapper动态代理,还需要定义一个与SQL映射文件对应的Dao接口。在大型工程的开发中,有时需要创建很多的Java实体类和SQL映射文件,以及Dao接口,而且很多时候,除了负责的业务SQL外,还需要重复编写每一个表的基本增、删、改、查SQL配置,这会降低开发效率。
对于这个问题,MyBatis官方提供了一种名为“逆向工程”的机制,其可以针对数据库中的单表自动生成MyBatis执行所需要的代码(包括Java实体类、SQL映射文件配置及Dao接口)。使用逆向工程,可以大大减少重复的配置和创建工作,提升开发效率。
2、MyBatis逆向工程环境搭建
2.1 导入jar包
要使用MyBatis逆向工程,除了需要MyBatis本身的依赖jar包外,还需要下载MyBatis逆向工程相应的依赖jar包。这里使用版本为1.3.2,名为“mybatis-generator-core-1.3.2.jar”的依赖jar包。将该jar包拷贝到WEB-INF/lib下,并添加为工程依赖(Add as Library)
2.2 创建数据库测试数据表
在mybatis数据库中创建名为“goods”的商品数据表,并在该表中添加测试数据。具体的建表和添加测试数据SQL语句如下:
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `goods`
-- ----------------------------
DROP TABLE IF EXISTS `goods`;
CREATE TABLE `goods` (
`id` int(255) NOT NULL auto_increment,
`name` varchar(255) default NULL,
`price` double(255,0) default NULL,
`number` int(255) default NULL,
`type` varchar(255) default NULL,
`no` varchar(255) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of goods
-- ----------------------------
INSERT INTO `goods` VALUES ('1', 'Bose QC35II', '2889', '50', '耳机', 'EJ456138');
INSERT INTO `goods` VALUES ('2', 'SKII 神仙水', '1035', '20', '化妆品', 'MZ789463');
INSERT INTO `goods` VALUES ('3', 'NIKE KD 15', '1689', '30', '鞋类', 'XZ459317');
创建完成后的goods数据表如下所示:
2.3 创建逆向工程配置文件
逆向工程如何做到由数据库生成相关的Java代码及配置文件呢?其实这些数据都编写在逆向工程配置文件generatorConfig.xml中。该配置文件会告诉逆向工程引擎,需要加载哪个数据库、哪些表,生成的Java实体类、SQL映射文件、Dao代理接口的位置,以及某些表中的数据对应的Java类型等。
在src下创建名为com.ccff.mybatis.mapper的包,该包用于存放通过MyBatis逆向数据生成的SQL映射文件。
在config文件夹下创建名为“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>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" 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:生成PO类的位置 -->
<javaModelGenerator targetPackage="com.ccff.mybatis.model"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="com.ccff.mybatis.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.ccff.mybatis.dao"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定数据库表 -->
<table tableName="goods">
<columnOverride column="price" javaType="java.lang.Double" />
<columnOverride column="name" javaType="java.lang.String" />
<columnOverride column="type" javaType="java.lang.String" />
<columnOverride column="no" javaType="java.lang.String" />
</table>
</context>
</generatorConfiguration>
在上面的配置文件中,首先加入MyBatis逆向工程的DTD格式声明,然后为generatorConfiguration标签对,其中放置逆向工程的主要配置。每一个context配置代表每一个单独的逆向配置。在context标签中:
commentGenerator标签: 定义了不生成注释的参数配置。
jdbcConnection标签: 配置了逆向工程需要连接的数据库信息。
javaTypeResolver标签: 主要指定JDBC中的相关类型,是否被强制转换成某种类型(默认false,把JDBC DECIMAL和 NUMERIC类型解析为Integer,为 true时把JDBC DECIMAL和NUMERIC类型解析为java.math.BigDecimal)。
javaModelGenerator标签: 配置了生成Java实体类的位置。
sqlMapGenerator标签: 配置了生成SQL映射文件的位置。
javaClientGenerator标签: 配置了生成Dao代理接口的位置。
table标签: 指定逆向工程操作的表信息,可以配置多个表信息。对于该标签,有些表中的某个字段需要被转换成指定的Java类型,那么可以在该table标签中添加单独对该类型的转换配置。例如在上述配置中对price字段的转换。
2.3 创建逆向执行类
编写完配置文件后,需要再创建执行类来加载配置文件,对数据表进行逆向工程的构建。
在src目录下创建名为“com.ccff.mybatis.generator”的包,该包下用于存储逆向工程执行类,在该包下创建名为“GeneratorSqlMap”的执行类,具体代码如下:
package com.ccff.mybatis.generator;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.api.ShellCallback;
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 GeneratorSqlMap {
public void generator() throws Exception{
//warnings为用于放置生成过程中警告信息的集合对象
List<String> warnings = new ArrayList<String>();
//指定DefaultShellCallback是否覆盖重名文件
boolean overwrite = true;
//加载配置文件
String path = "./config/generatorConfig.xml";
File configFile = new File(path);
//配置解析类
ConfigurationParser cp = new ConfigurationParser(warnings);
//配置解析类解析配置文件并生成Configuration配置对象
Configuration config = cp.parseConfiguration(configFile);
//DefaultShellCallback负责如何处理重复文件
ShellCallback callback = new DefaultShellCallback(overwrite);
//逆向工程对象
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
//执行逆向文件生成操作
myBatisGenerator.generate(null);
}
public static void main(String[] args) throws Exception {
GeneratorSqlMap generatorSqlmap = new GeneratorSqlMap();
generatorSqlmap.generator();
}
}
在该类中,首先使用FIle类生成generatorConfig.xml配置文件的File对象,然后创建用于解析配置文件的配置解析类ConfigurationParser,使用该类解析File对象,获取具体的配置对象Configuration。
然后创建ShellCallback对象,该对象主要负责把project属性或者package属性翻译成目录结构。还指定在生成文件时,在Java或者XML文件已经存在的情况下,如何处理这些重复的文件。ShellCallback接口的默认实现为org.mybatis.generator.internal.DefaultShellCallback,这个默认实现只负责把project和package直接翻译成文件结构,如果某些文件夹不存在,则创建。另外对于重复的文件,默认实现也只能选择覆盖或者忽略(overwrite参数设置为true,选择覆盖)。
接下来将config配置对象、callback处理对象及warnings警告信息集合对象,作为参数放入MyBatisGenerator的构造方法中,生成具体的逆向工程处理对象myBatisGenerator,然后执行generate方法进行逆向文件的生成。
2.4 执行逆向工程
运行GeneratorSqlMap类中的main方法来执行逆向方法,运行后可以发现工程生成了新的文件,目录发生了改变,具体如下所示:
可以看到,在com.ccff.mybatis.dao包下生成了名为“GoodsMapper”的Dao代理接口。在com.ccff.mybatis.mapper包下生成了名为“GoodsMapper.xml”的SQL映射文件。在com.ccff.mybatis.model包下生成了名为“Goods”的Java实体类和名为“GoodsExample”的查询包装类。
其中Dao代理接口和SQL映射文件中都定义了Goods最基本的增、删、改、查方法,以及其他常用的数据库操作(如数据统计),而Goods包装类即是数据库中goods表的字段的实体映射,GoodsExample是复杂查询或修改操作的条件包装。
在GoodsMapper代理接口中,countByExample方法根据传入的复杂条件封装类GoodsExample查询出结果总数;deleteByExample方法根据传入的复杂条件封装类GoodsExample删除符合条件的列;deleteByPrimaryKey方法根据传入的Integer类型的id删除该id对应的列;insert和insertSelective方法根据传入的Goods封装类在表中插入该商品信息;selectByExample方法根据传入的复杂条件封装类GoodsExample查询出符合条件的多个用户集合数据;selectByPrimaryKey方法根据传入的Integer类型的id查询单个用户信息;updateByExampleSelective和updateByExample方法根据传入的复杂条件封装类GoodsExample对符合条件的信息进行部分或全部修改;updateByPrimaryKeySelective和updateByPrimaryKey方法根据传入的Goods包装对象中的id属性查询符合条件的商品信息,并根据Goods包装类中的其他属性进行全部或部分修改。
生成的Dao接口文件如下:
package com.ccff.mybatis.dao;
import com.ccff.mybatis.model.Goods;
import com.ccff.mybatis.model.GoodsExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface GoodsMapper {
int countByExample(GoodsExample example);
int deleteByExample(GoodsExample example);
int deleteByPrimaryKey(Integer id);
int insert(Goods record);
int insertSelective(Goods record);
List<Goods> selectByExample(GoodsExample example);
Goods selectByPrimaryKey(Integer id);
int updateByExampleSelective(@Param("record") Goods record, @Param("example") GoodsExample example);
int updateByExample(@Param("record") Goods record, @Param("example") GoodsExample example);
int updateByPrimaryKeySelective(Goods record);
int updateByPrimaryKey(Goods record);
}
生成的SQL映射文件如下:
<?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.ccff.mybatis.dao.GoodsMapper" >
<resultMap id="BaseResultMap" type="com.ccff.mybatis.model.Goods" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="price" property="price" jdbcType="DOUBLE" />
<result column="number" property="number" jdbcType="INTEGER" />
<result column="type" property="type" jdbcType="VARCHAR" />
<result column="no" property="no" jdbcType="VARCHAR" />
</resultMap>
<sql id="Example_Where_Clause" >
<where >
<foreach collection="oredCriteria" item="criteria" separator