Spring+SpringMVC+MyBatis深入学习及搭建(十)——MyBatis逆向工程

转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6973266.html 

前面讲到:Spring+SpringMVC+MyBatis 深入学习及搭建 (九)——MyBatis 和 Spring 整合

使用官方网站的 mapper 自动生成工具 mybatis-generator-core-1.3.2 来生成 po 类和 mapper 映射文件。

1. 什么是逆向工程

mybatis 需要程序员自己编写 sql 语句,mybatis 官方提供逆向工程可以针对单表自动生成 mybatis 执行所需要的代码(mapper.java、mapper.xml、po...)

企业实际开发中,常用的逆向工程方式:

由数据库的表生成 java 代码。

2. 下载逆向工程

3. 使用方法(要求会用)

为了防止后期数据库表修改、扩展,需求修改等原因,更新自动生成的 po,mapper 覆盖有误。我们新建专门逆向生成的项目 generatorSqlmapCustom,再按需求将自动生成的 po,mapper 等拷贝到项目中去。

3.1 运行逆向工程

建议使用 java 程序方式,不依赖开发工具。

3.2mapper 生成配置文件

在 gengeratorConfig.xml 中配置 mapper 生成的详细信息,注意改下几点:

(1)添加要生成的数据库表;

(2)po 文件所在包路径;

(3)mapper 文件所在包路径。

配置文件如下:

<?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/mybatisdemo" userId="root"
password
="">
</jdbcConnection>
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg"
password="yycg">
</jdbcConnection>
-->

    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和 
        NUMERIC 类型解析为java.math.BigDecimal </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">javaTypeResolver</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="forceBigDecimals"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">javaTypeResolver</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> targetProject:生成PO类的位置 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">javaModelGenerator </span><span style="color: rgba(255, 0, 0, 1)">targetPackage</span><span style="color: rgba(0, 0, 255, 1)">="joanna.yan.po"</span><span style="color: rgba(255, 0, 0, 1)">
        targetProject</span><span style="color: rgba(0, 0, 255, 1)">=".\src"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> enableSubPackages:是否让schema作为包的后缀 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="enableSubPackages"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
        <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 从数据库返回的值被清理前后的空格 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="trimStrings"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="true"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">javaModelGenerator</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> targetProject:mapper映射文件生成的位置 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">sqlMapGenerator </span><span style="color: rgba(255, 0, 0, 1)">targetPackage</span><span style="color: rgba(0, 0, 255, 1)">="joanna.yan.mapper"</span><span style="color: rgba(255, 0, 0, 1)"> 
        targetProject</span><span style="color: rgba(0, 0, 255, 1)">=".\src"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> enableSubPackages:是否让schema作为包的后缀 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="enableSubPackages"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">sqlMapGenerator</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> targetPackage:mapper接口生成的位置 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">javaClientGenerator </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="XMLMAPPER"</span><span style="color: rgba(255, 0, 0, 1)">
        targetPackage</span><span style="color: rgba(0, 0, 255, 1)">="joanna.yan.mapper"</span><span style="color: rgba(255, 0, 0, 1)"> 
        targetProject</span><span style="color: rgba(0, 0, 255, 1)">=".\src"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> enableSubPackages:是否让schema作为包的后缀 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">p    </span><span style="color: rgba(255, 0, 0, 1)">roperty name</span><span style="color: rgba(0, 0, 255, 1)">="enableSubPackages"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="false"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">javaClientGenerator</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定数据库表 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">table </span><span style="color: rgba(255, 0, 0, 1)">tableName</span><span style="color: rgba(0, 0, 255, 1)">="items"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">table</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">table </span><span style="color: rgba(255, 0, 0, 1)">tableName</span><span style="color: rgba(0, 0, 255, 1)">="orders"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">table</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">table </span><span style="color: rgba(255, 0, 0, 1)">tableName</span><span style="color: rgba(0, 0, 255, 1)">="orderdetail"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">table</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">table </span><span style="color: rgba(255, 0, 0, 1)">tableName</span><span style="color: rgba(0, 0, 255, 1)">="user"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">table</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> &lt;table schema="" tableName="sys_user"&gt;&lt;/table&gt;
    &lt;table schema="" tableName="sys_role"&gt;&lt;/table&gt;
    &lt;table schema="" tableName="sys_permission"&gt;&lt;/table&gt;
    &lt;table schema="" tableName="sys_user_role"&gt;&lt;/table&gt;
    &lt;table schema="" tableName="sys_role_permission"&gt;&lt;/table&gt; </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 有些表的字段需要指定java类型
     &lt;table schema="" tableName=""&gt;
        &lt;columnOverride column="" javaType="" /&gt;
    &lt;/table&gt; </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">context</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</generatorConfiguration>

3.3 使用 Java 类生成 mapper 文件

public class GeneratorSqlmap {
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> generator() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Exception{
    List</span>&lt;String&gt; warnings = <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList&lt;String&gt;<span style="color: rgba(0, 0, 0, 1)">();
    </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> overwrite = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">指定 逆向工程配置文件</span>
    File configFile = <span style="color: rgba(0, 0, 255, 1)">new</span> File("generatorConfig.xml"<span style="color: rgba(0, 0, 0, 1)">); 
    ConfigurationParser cp </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ConfigurationParser(warnings);
    Configuration config </span>=<span style="color: rgba(0, 0, 0, 1)"> cp.parseConfiguration(configFile);
    DefaultShellCallback callback </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> DefaultShellCallback(overwrite);
    MyBatisGenerator myBatisGenerator </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MyBatisGenerator(config,
            callback, warnings);
    myBatisGenerator.generate(</span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);

} 
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> main(String[] args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Exception {
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        GeneratorSqlmap generatorSqlmap </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> GeneratorSqlmap();
        generatorSqlmap.generator();
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
        e.printStackTrace();
    }
}

}

 生成后的代码:

3.4 拷贝生成的 mapper 文件到工程中指定的目录中

3.4.1mapper.xml

Mapper.xml 文件拷贝至 mapper 目录内

3.4.2mapper.java

Mapper.xml 文件拷贝至 mapper 目录内

注意:mapper.xml 文件和 mapper.java 文件在一个目录内且文件名相同。

3.4.3mapper 接口测试

public class ItemsMapperTest {
    private ApplicationContext applicationContext;
    private ItemsMapper itemsMapper;
@Before
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setUp(){
    applicationContext</span>=<span style="color: rgba(0, 0, 255, 1)">new</span> ClassPathXmlApplicationContext("classpath:spring/applicationContext.xml"<span style="color: rgba(0, 0, 0, 1)">);
    itemsMapper</span>=(ItemsMapper) applicationContext.getBean("itemsMapper"<span style="color: rgba(0, 0, 0, 1)">);
}

@Test
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> testInsert() {
    Items item</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Items();
    item.setName(</span>"手机"<span style="color: rgba(0, 0, 0, 1)">);
    item.setPrice(999f);<br>     item.setCreatetime(new Date());
    itemsMapper.insert(item);
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">自定义条件查询</span>

@Test
public void testSelectByExample() {
ItemsExample itemsExample
=new ItemsExample();
//通过 criteria 构造查询条件
ItemsExample.Criteria criteria=itemsExample.createCriteria();
criteria.andNameEqualTo(
"笔记本 3");
//可能返回多条记录
List<Items> list=itemsMapper.selectByExample(itemsExample);
System.out.println(list);
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">根据主键查询</span>

@Test
public void testSelectByPrimaryKey() {
Items items
=itemsMapper.selectByPrimaryKey(1);
System.out.println(items);
}

@Test
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> testUpdateByPrimaryKey() {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">对所有字段进行更新,需要先查询出来再更新</span>
    Items items=itemsMapper.selectByPrimaryKey(1<span style="color: rgba(0, 0, 0, 1)">);
    items.setName(</span>"水杯"<span style="color: rgba(0, 0, 0, 1)">);
    itemsMapper.updateByPrimaryKey(items);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">如果传入字段不为空才更新,在批量更新中使用此方法,不需要先查询再更新</span>

itemsMapper.updateByPrimaryKeySelective(items);
}

}

4. 逆向工程注意事项

4.1Mapper 文件内容不覆盖而是追加

XXXMapper.xml 文件已经存在时,如果进行重新生成则 mapper.xml 文件内容不被覆盖而是进行内容追加,结果导致 mybatis 解析失败。

解决方法:删除原来已经生成的 mapper.xml 文件再进行生成。

MyBatis 自动生成的 po 和 mapper.java 文件不是内容追加而是直接覆盖没有此问题。

4.2 Table schema 问题

下边是针对 Oracle 数据库表生成代码的 schema 问题:

schema 即数据库模式,oracle 中一个用户对应一个 schema, 可以理解为用户就是 schema。当 Oracle 数据库存在多个 Schema 可以访问相同的表名时,使用 mybatis 生成该表的 mapper.xml 将会出现 mapper 内容重复的问题,结果导致 mybatis 解析错误。

解决方法:在 table 中填写 schema, 如下:

<table schema="XXXX" tableName=" " >

XXXX 即为一个 schema 的名称,生成后将 mapper.xml 的 schema 前缀批量去掉,如果不去掉,当 Oracle 用户变更了 sql 语句将查询失败。

快捷操作方式:mapper.xml 文件中批量替换:“from XXXX.”为空。

Oracle 查询对象的 schema 可从 dba_objects 中查询,如下:

select * from dba_objects

如果此文对您有帮助,微信打赏我一下吧 ~