Mybatis的学习 0. MyBatis Generator

好吧,学习个MyBatis Generator就用了这么长时间,这个SSM看来还是比较麻烦的

2016-03-15 | 阅读

Mybatis

MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀的持久化框架,MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录.

使用Mybatis-Generator

使用Mybatis-Generator这个maven插件来快速生成mapper类,mapper配置文件和Model类.中文文档

MyBatis GeneratorMyBatis的代码生成器.可以自动查询数据库中的所有表,然后生成可以访问表的基础对象类型.解决了对数据库操作有最大影响的一些简单的CRUD增删改查操作,但是仍需要对联合查询和存储过程手写SQL语句和对象.

MyBatis Generator 会生成三种对象:

  1. 匹配表结构的POJO对象,可能有以下4种类型:

    • 一个基本的对象类型,含有单字段的主键,和BLOB类型除外的所有基本字段类型
    • 允许动态查询更新删除的类,后缀Example.
    • 如果设置defaultModelTypeconditional,且含有联合主键,则会生成一个后缀key的实体类,只含有联合主键.如果设置defaultModelTypehierarchical,且含有主键,也会单独为主键生成一个key对象.
    • 如果存在blob类型的字段,且defaultModelTypehierarchical ,就会为所有blob属性单独生成一个对象,后缀为WithBLOBs.
  2. 为每个表的简单CRUD操作生成SQL语句,存放在XML文件中,也就是Mapper.xml文件.生成的sql语句包括:

    • insert 插入
    • update by primary key 根据主键更新记录
    • update by example 根据条件更新记录
    • delete by primary key 根据主键删除记录
    • delete by example 根据条件删除
    • select by primary key 根据主键查询
    • select by example 根据条件查询
    • count by example 根据条件查询记录总数

    根据表的结构,生成语句会有不同,如表中没有主键时,不会生成根据主键的方法.

  3. java客户端中,MGB会为 MyBatis 3.x生成:

    一个可以与 MyBatis 3.x一起使用的mapper接口类.

两个比较重要的事情:

  • MBG运行生成的新的XML会与已经存在的进行自动合并,所以,如果对XML进行了自定义的更改,则不用担心这些修改会丢失.
  • MGB不会合并java文件,会直接覆盖文件,所以要手动合并这些更改.

以Maven插件的形式运行 MyBatis Generator

在Maven项目的Pom.xml文件的build下添加插件:

 <plugin>
          <groupId>org.mybatis.generator</groupId>
          <artifactId>mybatis-generator-maven-plugin</artifactId>
          <version>1.3.2</version>
          <configuration>
              <verbose>true</verbose>
              <overwrite>true</overwrite>
          </configuration>
          <dependencies>
          <dependency>
              <groupId>org.mariadb.jdbc</groupId>
              <artifactId>mariadb-java-client</artifactId>
              <version>1.3.6</version>
          </dependency>
          </dependencies>
      </plugin>

其常用的参数有:

  • configurationFile 指定配置文件的名称,默认是 ${basedir}/src/main/resources/generatorConfig.xml
  • contexts 指定哪些context会被执行,如果没有设置该参数,所有的context都会被执行.
  • overwrite 指定该参数,则生成java文件时,直接覆盖原来的文件.默认是false,即会对生成的java文件进行编号来标记不是相同的执行结果,由用户来自行合并java文件.
  • tableNames 如果指定了该参数,则只有指定的这些表会被运行.
  • verbose 如果指定该参数,则会输出执行过程.

运行时,应该先清空之前文件夹内的内容,然后再进行生成,不会自动清空之前的文件夹内容.这里要做一些思考.

注意,这里在MyBatis Generator中有一个依赖,依赖的是JDBC驱动,这样做的原因,这样依赖,就会让jdbc的jar位于MyBatis Generator插件的classpath中,直接就可以通过fully qualified class name来访问jdbc,也就不用设置之后的<classPathEntry>标签了.

执行Mybatis Generator后

执行MBG后,需要修改MyBatis的配置文件.修改 MapperConfig.xml文件.

MapperConfig.xml文件中,指定MBG生产的XML映射文件.在<mappers>标签下:

##wating.

也可以直接通过 MapperConfigPlugin插件来生产一个 Mapper配置文件的骨架,需要在设置的plugins标签下进行设置.

generatorConfig.xml 详细配置

首先从层次上来说明,配置文件,有一个根元素generatorConfiguration和三个子元素.

  • 根元素为<generatorConfiguration>,包含子元素(按照严格的顺序):<properties>(0或一个),<classPathEntry>(0或多个),<context>(1或多个);
  • <properties>,指定外部的属性文件,然后在配置中就可以通过${xxproperty}来引用属性文件中的属性值了.属性可以通过resource或者url来指定.前者指定classpath下的属性文件,后者一般通过file协议来加载指定路径位置的属性文件,如:<properties url="file:///xxx/jdbc.properties"/>
  • classPathEntry元素,一般来指定驱动路径.属性location,来指定jdbc驱动包的位置.如果将jar包放入了classpath中,就不用设置这个属性了.
  • context元素:用于指定一组对象的环境.子元素用于指定连接到的数据库,要生成的对象的类型和要处理的数据库中的表.该元素只有一个必选属性id,来进行唯一标识.

<context>还有可选属性:

  • defaultModelType : 设置MBG如何生成实体类.conditional默认值,不会生成单独的Blob实体类,但是如果有联合主键,会生成一个主键实体类.flat,只生成一个实体类.hierarchical,如果有联合主键,会生成单独的主键实体类,如果有Blob字段,会生成单独的Blob实体类,然后还会有一个普通实体类.
  • targetRuntime : 这个属性用于指定生成代码的运行时目标.
    1. MyBatis3 : 输出对象兼容MyBatis 3.0或更高版本,兼容JSE 5.0或更高版本的对象,包含泛型和注解.会生成 by example这类动态查询方法.
    2. MyBatis3Simple: 与上面的MyBatis3类似,但是不会生成by example`一类方法,只有少量的动态SQL.
    3. Ibatis2Java2IbaitsJava5:略.

然后在<context>有子元素:

  • <property> (0..N) ,property以name,和value的形式来设置,支持的属性有:

    • autoDelimitKeywords : 自动识别数据库关键字,默认为false,设置为true后,如果遇到数据库关键字,用<columnOverride>替换.
    • beginnginDelimiter , endingDelimiter : 用作分隔符的符号,oracle中是”,而mysql中是’
    • javaFileEncoding : 设置Java文件的编码集,如果没有指定,则会使用系统默认编码.
    • javaFormatter : 使用该属性来指定生成的java文件的用户指定的formater的完整的类名称,用于格式化java代码,这个类必须继承org.mybatis.generator.api.JavaFormatter,而且提供一个默认不含参数的构造方法.每个context持有一个单独的javaFormatter实例,默认的是org.mybatis.generator.api.dom.DefaultJavaFormatter,默认格式使用内脏到 Java DOM类的格式.
    • xmlFormatter : 格式化xml文件,与上述javaFormatter类似.
  • <plugin> (0..N)

    用来定义一个插件,插件用于修改MBG生成的代码.类继承于 org.mybatis.generator.api.Plugin.

  • <commentGenerator> (0 or 1)

    用于定义注释生成器的属性.注释生成器用来给由MBG生成的多种元素,Java自动,java方法,XML元素等等 生成注释. 默认的注释生成器将JavaDoc注释添加到所有生成的Java元素上,也会添加到每个生成的XML元素上.注释的目的是告诉用户这个元素是生成的,并且有可能重新生成,也就是说不应该修改这些地方.

    可选属性 type,用来指定注释生成器类型.自定义的类要继承于 org.mybatis.generator.api.CommentGenerator.

    使用子元素来设置属性:

    • suppressAllComments : 用来指定MBG所生成的代码是否包含任何注释.默认为false,即都会生成注释.为true是,所有代码都不会生成注释,且代码不会并合并.
    • suppressDate : 用来指定生成的注释中是否包含生成的日期.默认为false. 设置为true,不会添加时间戳.
  • <jdbcConnection> (1 Required)

    设置数据库连接的属性.每个必须含有一个元素. 必选属性:

    • driverClass : 访问数据库的JDBC驱动程序的完全名称.
    • connectionURL : 用于访问数据的JDBC连接URL.

    可选属性:

    • userId : 访问数据库的用户ID
    • password : 访问数据库的密码

    可以设置子元素<property>,指定的属性都会被添加到JDBC驱动程序的属性中.

  • <javaTypeResolver> (0 or 1)

    java类型处理器,处理数据库中类型到Java中的类型.使用属性type来设置,默认使用JavaTypeResolverDefaultImpl来处理类型.

    子元素property支持一个属性:

    forceBigDecimals : 是否强制将DECIMALNUMERIC的类型转换为BigDecimal类型,默认是false.

    默认情况下的转换规则为:

    1. 如果精度>0或者长度>18,使用BigDecimal.
    2. 如果精度=0且10<=长度<=18,则使用Long
    3. 如果精度=0且5<=长度<=9,则使用Integer
    4. 如果精度=0且长度<5 ,则使用Short.
  • <javaModelGenerator> (1 Required)

    该元素用于控制生成的实体类.有两个必选属性:

    • targetPackage : 生成实体类所在的包名.会为目标包名生成pacakge.
    • targetProject : 指定目标项目,运行于Eclipse或者IDEA等IDE时,这个属性是来指定项目的source root,一般就是 src/main/java这样的路径.不会为这个路径创建文件夹.

    通过子元素来设置属性:

    • constructorBased : 是否为每个类生成一个使用所有字段的构造函数.只对MyBatis3有效,默认为false. 如果属性immutable被设置了,则这个属性会被忽略.可以在<table>中对具体的一个表进行设置.
    • enableSubPackages : 是否根据表的 catalog 和 schema 来生成一个子包,默认是false.
    • immutable : 这个属性用于选择这些类是否是可变的,如果设置true,则这些类是不可变的,所有没有setter方法,且会忽略constructorBased属性,来默认提供一个含有所有参数的构造函数.默认是false.
    • rootClass : 这个属性用来指定所有生成的Java Model的基类,需要使用 fully qualified class namecom.xxx.xxx.RootClass. 如果生成对象生成的类型或者getter和setter方法在RootClass中存在,则不会自动生成和覆盖rootClass中的内容.
    • trimStrings : 这个属性用来设置对从数据库取回的字符串进行trim操作,默认为false.
  • <sqlMapGenerator> (0 or 1)

    定义SQL映射生成器的属性,SQL映射生成器会为每个表生成Mybatis使用的XML文件.如果没有指定这个元素,不会生成SQL映射的XML文件.如果使用MyBatis3,且设置了javaClientGenerator需要XML时,这个属性回事必选子元素.

    可选属性:

    • targetPackage : 包所在位置
    • targetProject : 指定目标项目

    可以通过子元素 来设置一个属性 :enableSubPackages:是否通过目录和schema来生成子包.

  • <javaClientGenerator> (0 or 1)

    用于定义Java客户端代码生成器的属性.会生成Java的接口和类,可以简单的使用生成的Java Model和XML映射文件.在MyBatis中,会生成Mapper接口形式的代码.

    必选属性:

    • type : 用户选择一个默认的生成器,或者使用用户自定义的DAO生成器.自定义需要继承与 org.mybatis.generator.codegen.AbstractJavaClientGenerator类. 如果当前targetRuntime是 MyBatis3,有以下三个选项:

      • ANNOTATEDMAPPER : 生成对象是 MyBatis3.x 映射器基础结构的Java接口,这些接口会基于注解和SqlProviders,不会有XML文件生成.就是纯接口使用注解.会有Provider生成.
      • MIXEDMAPPER : 注解与XML混合,注解用在简单注解可以实现的地方,客户端不会生成SqlProvider,复杂的动态SQL都会生成在XML中.
      • XMLMAPPER : 生成接口依赖XML文件.

      如果targetRuntime是MyBatis3Simple没有MIXEDMAPPER选项.

    • targetPackage和targetProject

    可选属性 :

    • implementationPackage : 如果指定了该属性,实现类就会生成在这个包中.

    通过子元素 来设置属性:

    • enableSubPackages : 是否根据 catolog和scheme来生成不同的包.
    • exampleMethodVisibility : 设置byExample方法是否可见,默认是public,可见,且在接口中声明方法.可以设置的属性有: public,private,protected,default,但是在MyBatis3中,忽略该属性.
    • methodNameCalculator : 属性用于为DAO方法提供不同的名称.被Mybatis3忽略.
    • rootInterface : 指定是否所有生成的接口都继承与一个父接口.使用 fully qualified class name.
    • useLegacyBuilder : 默认是false.设置为true,会使用SqlBuilder为MyBatis生成动态SQL,在MyBatis3.2和以后被弃用.如果为false,则使用新的SQL生成器来生成客户端代码.
  • <table> (1..N)

    从数据库中选择一个表,来生成对象.

    必选属性:

    tableName : 数据库表的名称,不包含 catalog和schema,可以指定SQL通配符,如”%”来匹配所有的表.名称的匹配的逻辑:如果名称中有空格,则以指定大小写来查找表,如果数据库标识为大写,则用大写,如果数据库标识为小写则用小写,否则,自行定义.在创建数据库时,如果使用”“来指定大小写了,即使数据库标识符是大写,也需要设置 delimitIdentifiers = "true"来保留大小写格式.

    可选属性:

    • schema : 可以指定通配符
    • catalog : 可以指定通配符
    • alias : 如果指定,则设置的别名会用在select查询上.
    • domainObjectName : 生成的对象的基本名称,如果没有指定,则会以表名来命名.由于带domain,所以可以生成到指定包中,如 abc.Model,对象名是Model,添加到包abc中.
    • enableInsert : 是否生成Insert语句,默认为true.
    • enableSelectByPrimaryKey : 是否生成根据主键查询语句,默认为true.如果不存在主键,这不会生成根据主键查询的语句.
    • enableSelectByExample : 是否通过 Example进行动态查询.默认为true.
    • enableUpdateByPrimaryKey : 是否通过主键根据.默认为true
    • enableDeleteByPrimaryKey : 是否通过主键删除语句.默认为true.
    • enableUpdateByExample : 是否生成通过Example更新语句.默认为true.
    • enableDeleteByExample : 是否生成通过Example删除语句,默认为true.
    • enableCountByExample : 是否生成根据Example查询总数的语句,默认为true.
    • selectByPrimaryKeyQueryId : 这个值会以 <value> as QUERYID的形式被添加到主键查询语句的select列中.这样,可以对生成的每一个查询指定一个唯一的ID.
    • selectByExampleQueryId : 对每一次查询设置一个唯一id.
    • modelType : 可以用来重写默认的模型类型,即conditional,flat,和hierarchical三个属性.
    • escapeWildcards : 这个属性表示当查询列时,是否对schema和表名中的SQL通配符(如_和%)进行转义.默认是false.
    • delimitIdentifiers : 这个属性当查询表并且在生成的SQL中分割标识符时,是否使用指定的确切值.默认为false.如果catalog,schema或者tableName包含空白时,应该为true.
    • delimitAllColumns : 指示是否给生成SQL中所有的列名添加分割符.默认为false.

    子元素有 :

    • <property> (0 .. N) : 通过property可以设置以下属性:

      • construtorBased : 是否产生一个含有所有字段的构造函数.默认为false
      • ignoreQualifiersAtRuntime : 生成的SQL的表名将不会包含schema和catalog的前缀.默认为false.
      • immutable : 与<javaModelGenerator>中含义相同.
      • modelOnly : 是否值生成模型类,而不生成CRUD方法.默认是false.
      • rootClass : 与<javaModelGenerator>中含义相同.
      • rootInterface : 与<javaModelGenerator>中含义相同.
      • runtimeCatalog : 指定生成SQL语句中的catalog,生成代码的catalog会与运行时的catalog不同.
      • runtimeSchema : 运行时 schema
      • runtimeTableName : 运行时表名.
      • selectAllOrderByClause : 在MyBatis3SseColimple中,将这个属性以 oder by的形式添加到selectAll方法中.
      • useActualColumnNames : 默认为false.设置为true时,将从数据库元数据获取的列名作为实体类的属性名.false时,会将名称转换为驼峰形式.如果被<columnOverride>元素指定,则会忽略这个属性. 如START_DATE属性会变成 startDate属性.
      • useColumnIndexes : 默认为false.且Mybatis3中不支持这个属性.如果为true,会在生成resultMaps时使用索引.
      • useCompoundPropertyNames : 默认为false. 如果为true,在生成属性名时,会将列名和备注连接起来.
    • <generatedKey> (0 or 1) :

      用于指定自动生成主键的属性.如果指定该元素,MBG会在生成insert的SQL映射文件中插入一个合适的<selectKey>元素.简单来说,就是可以用来做自增主键的设置.

      必选属性:

      • column : 生成列 的列名.
      • sqlStatement : 返回新值的SQL语句.一些特殊值为 :MySql,转化为`SELECT LAST_INSERT_ID() . JDBC在MyBatis3中,生成正确的代码,且脱离数据库的限制.

      可选属性:

      • identity : 默认为false.如果为true,被标记为identity列,且<selectKey>元素后被插入在insert后面.如果为false,则会被插入在insert之前.
      • type : 为selectKey元素指定类型, pre或post.指定类型后,selectKey永远在insert语句之前.

      理解这个序列的意思,和插入前后的意思.序列表示表是一个序列,插入之前要先查询表,就需要知道当前指向的位置即主键.而自增主键要在插入之后,才能知道自己的大小.

    • <columnRenamingRule> (0 or 1)

      列的重命名规则.MBG使用正则表达式来进行重命名规则的实现,如果有<columnOverride>,则忽略<columnRenamingRule>属性.先使用这个重命名规则后,获得的结果再去使用useActualColumnNames规则来判断是非需要再次更新属性名.

      必选属性:

      searchString : 定义将被替换的子字符串的正则表达式.

      可选属性:

      replaceString : 替换匹配的字符串.如果没有设置,则用空字符串替换.

    • <columnOverride> (0 … N)

      将默认得到的列进行修改,来设置指定的类型,名称等.

      必选属性:

      column : 列名

      可选属性:

      • property : 要使用的Java名称.
      • javaType : 完全指定的Java类型.这里有必要来处理奇怪的数据库类型,如mysql中的unsigned bigint需要被映射为java.lang.Object.
      • jdbcType : 该列的JDBC类型(INTEGER,DECIMAL等等)
      • typeHandler : 用户定义的需要用来处理该列的类型处理器.
      • delimitedColumnName : 是否需要分割列名,指的是列名可能是带空格或者保留字,所以是否需要添加分隔符.默认为false.
    • <ignoreColumn> (0 … N)

      忽略的列.可选属性:

      delimitedColunmnName : 当匹配对从数据库返回列时,是否区分大小写.默认为false.

生成的对象 Example类的使用

Example类指定了构建一个动态查询语句,where子句里只能包含非 BLOB列.

Example类内包含一个内部静态类Criteria,Criteria包含了一个用anded组合的where子句中的条件列表.Example类包含一个List<Criteria>属性,所有子句都是以ored组合在一起,使用不同属性的Criteria来生成各种条件的查询语句.可以通过or()来创建Criteria对象,如:

TestTableExample example = new TestTableExample();
example.or().andField1EqualTo(5);

对于复杂的查询,如下例:

TestTableExample example = new TestTableExample();

  example.or()
    .andField1EqualTo(5)
    .andField2IsNull();

  example.or()
    .andField3NotEqualTo(9)
    .andField4IsNotNull();

  List<Integer> field5Values = new ArrayList<Integer>();
  field5Values.add(8);
  field5Values.add(11);
  field5Values.add(14);
  field5Values.add(22);

  example.or()
    .andField5In(field5Values);

  example.or()
    .andField6Between(3, 7);

在上面的例子中, 动态生成的where子句是:

where (field1 = 5 and field2 is null)
 or (field3 <> 9 and field4 is not null)
 or (field5 in (8, 11, 14, 22))
 or (field6 between 3 and 7)

去重复,在Example类中调用setDistinct(true).

Criteria 内部类的每个属性都包含 andXXX 方法,以及如下的标准的SQL查询方法:

  • IS NULL - 指相关的列必须为NULL
  • IS NOT NULL - 指相关的列必须不为NULL
  • = (equal) - 指相关的列必须等于方法参数中的值
  • <> (not equal) - 指相关的列必须不等于方法参数中的值
  • > (greater than) - 指相关的列必须大于方法参数中的值
  • >= (greater than or equal) - 指相关的列必须大于等于方法参* 数中的值
  • < (less than) - 指相关的列必须小于于方法参数中的值
  • <= (less than or equal) - 指相关的列必须小于等于方法参数中的值
  • LIKE - 指相关的列必须 “like” 方法参数中的值. 这个方法不用必须加入 ‘%’, 您必须设置方法参数中的值.
  • NOT LIKE - 指相关的列必须 “not like” 方法参数中的值. 这个方法不用必须加入 ‘%’, 您必须设置方法参数中的值.
  • BETWEEN - 指相关的列必须在 “between” 方法参数中的两个值之间.
  • NOT BETWEEN - 指相关的列必须不在 “not between” 方法参数中的两个值之间.
  • IN - 指相关的列必须在传入的方法参数的list中.
  • NOT IN - 指相关的列必须不在传入的方法参数的list中.

MyBatis Generator使用的一些心得

  • 可以考虑实体类类型defaultModelTypeflat,即只有一个对象,这样管理起来更加方便.
  • 注释的时间戳suppressDate一般都会关闭,因为每次重新生成都会修改时间戳,SVN都要重新提交,不利于多人开发.
  • 将jdbc驱动放在项目的classPath下,而不是使用<classPathEntry>来引入jar包.
  • 对于字符串类型,一般都设置trimStrings来去除空格.
  • <table>中配置<generatedKey>,来实现自增主键.
  • 在Mysql中,支持无符号数,但是java中的数据类型都是有符号的,所以要用<columnOverride>来解决这个问题,先将类型转换成 java.lang.Object,然后在使用时,将返回值强制转换为适当的类型.

一个简单的示例

首先在JDBC配置文件处,对项目文件夹布局进行指定:

# 包路径配置
model.package=com.lxm.ssm.pojo
dao.package=com.lxm.ssm.dao
xml.mapper.package=com.lxm.ssm.mapping
target.project=src/main/java

然后再编写这个插件的配置文件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>
    <!-- 配置文件路径 -->
    <properties url="file:///Users/luoxianming/IdeaProjects/SSM123/src/main/resources/jdbc.properties"/>

    <context id="MySQLTables" targetRuntime="MyBatis3" defaultModelType="hierarchical">
        <!--关闭时间注释 -->
        <commentGenerator>
            <property name="suppressDate" value="true"/>
        </commentGenerator>

        <!--数据库连接信息 -->
        <jdbcConnection driverClass="${driver}" connectionURL="${url}" userId="${username}"
                        password="${password}">
        </jdbcConnection>

        <!--生成的model 包路径 -->
        <javaModelGenerator targetPackage="${model.package}" targetProject="${target.project}">
            <property name="enableSubPackages" value="ture"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!--生成xml mapper文件 路径 -->
        <sqlMapGenerator targetPackage="${xml.mapper.package}" targetProject="${target.project}">
            <property name="enableSubPackages" value="ture"/>
        </sqlMapGenerator>

        <!-- 生成的Dao接口 的包路径 -->
        <javaClientGenerator type="ANNOTATEDMAPPER" targetPackage="${dao.package}" targetProject="${target.project}">
            <property name="enableSubPackages" value="ture"/>
        </javaClientGenerator>

        <!--对应数据库表名 -->
        <table tableName="%">
            <generatedKey column="id" sqlStatement="Mysql"/>
        </table>


    </context>
</generatorConfiguration>