mybatis系列总结

mybatis 简介

Hibernate是当前最流行的 O/R mapping框架。mybatis 是一种"Sql Mapping"的ORM实现。
Hibernate对数据库结构提供较为完整的封装,实现POJO和数据库表之间的映射,以及SQL的自动生成和执行。只需定义好POJO到数据库表的映射关系,即可通过 Hibernate 提供的方法完成持久层操作。甚至不需要对SQL的熟练掌握,Hibernate/OJB会根据制定的存储逻辑,自动生成对应的 SQL并调用JDBC接口加以执行。
mybatis的着力点,则在于POJO与SQL之间的映射关系。iBATIS并不会在运行期自动生成SQL执行。具体的SQL需要程序员编写,然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。使用mybatis提供的ORM机制,对业务逻辑实现人员而言,面对的是纯粹的Java对象,这一层与通过Hibernate 实现ORM而言基本一致,而对于具体的数据操作,Hibernate会自动生成SQL语句。相对 Hibernate而言,mybatis以SQL开发的工作量和数据库移植性上的让步,为系统设计提供更大的自由空间。

mybatis 与 hibernate 区别

  • mybatis 简单易学,轻量;Hibernate相对较复杂,门槛较高,设计O/R映射,在性能和对象模型之间如何权衡取得平衡。Hibernate功能强大,数据库无关性好,O/R映射能力强。
  • 当系统属于二次开发,无法对数据库结构做到控制和修改,那mybatis的灵活性将比Hibernate更适合。
  • 系统数据处理量巨大,性能要求极为苛刻,这往往意味着必须通过经过高度优化的SQL语句(或存储过程)才能达到系统性能设计指标。在这种情况下mybatis会有更好的可控性和表现。mybatis比Hibernate更容易进行sql的优化。鉴于一般系统性能的瓶颈都在数据库上,所以这一点是mybatis非常重要的一个优势。
  • mybatis 需要手写sql语句,也可以生成,Hibernate则基本上可以自动生成,偶尔会写一些Hql。同样的需求,mybatis 的工作量比Hibernate要大很多。类似的,如果涉及到数据库字段的修改,Hibernate修改的地方很少,而mybatis 要把那些sql mapping的地方一一修改。
  • 运行效率:在不考虑cache的情况下,mybatis 应该会比hibernate快一些或者很多(根据实际情况会有所不同)。

com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column ‘blah’ at row 1

mybatis + MySQL 存储数据时遇到上面的报错,第一反应是去检查数据库表的DDL语句,以及查看待执行的 SQL 语句,但是两者都没有问题。最后才发现 mybatis 的 mapper.xml 文件里面的需要严格对应起来,即顺序

 <insert id="insert" parameterType="SomePO">
    INSERT INTO order_data (
      DemandOrderId, OrderFromWeight, OtherRequirementWeight, InterceptWeight)
    VALUES  (
      #{po.demandOrderId},
      #{po.orderFromWeight},
      #{po.interceptWeight},
      #{po.otherRequirementWeight})
insert>

     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

比如上面的sampleMapper.xml 文件的写法有问题,

mybatis mapper xml 特殊符号转义写法

<          <   小于
<=         <=   小于或等于
>          >    大于
>=        >=    大于或等于
<>   <>   不等于
&      & 
'      '
"      "

     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

也可以使用<[CDATA[ ]]>符号进行说明,将此类符号不进行解析,比如写 < > = 等:

MySQL like的写法
like concat('%',#{param},'%') 或者 like '%${param}%',推荐使用前者,可以避免SQL注入。

Mybatis 模糊查询 MySQL 中记录的三种常用方法

以MySQL数据库为例(不同的数据库,有些可能不支持)
常用的模糊查询有三种方法:

  1. 直接使用 % 拼接字符串,如'%'#{name}'%'"%"#{name}"%",单引号或双引号都可以。
  2. 使用concat(str1,str2)函数拼接
  3. 使用mybatis的bind标签

示例:在userMapper.xml文件中新建映射sql的标签:


<select id="getUsersByFuzzyQuery" parameterType="User" resultType="User">
    select <include refid="columns"/> from users
    <where>
        
        <if test="name != null">
            name like "%"#{name}"%"
        if>
        
        <if test="phone != null">
            and phone like concat(concat("%",#{phone}),"%")
        if>
        
        <if test="email != null">
            <bind name="pattern" value="'%'+email+'%'"/>
            and email like #{pattern}
        if>
    where>
select>

     
     
     
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

java.lang.IllegalArgumentException: Result Maps collection already contains value for *

常规的SSM应用启动失败,报错:

Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.lang.RuntimeException: Error parsing Mapper XML. Cause: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for GeographyMapper.getByCode.

     
     
     
     
  • 1

定位原因是在 mybatis 的 mapper.xml 文件里面有重复的 id 定义。

  
<select id="getByCode" resultType="Geography"  
    parameterType="java.lang.String">  
    select * from Geography where code = ${code}  
select>

<plugin> <groupId>org.mybatis.generatorgroupId> <artifactId>mybatis-generator-maven-pluginartifactId> <version>1.3.7version> <configuration> <configurationFile>${basedir}/src/main/resources/mybatis/generatorConfig.xmlconfigurationFile> <verbose>trueverbose> <overwrite>trueoverwrite> configuration> plugin>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  1. 新增 generatorConfig.xml:


<generatorConfiguration>
    
    
<!--指定特定数据库的jdbc驱动jar包的位置 -->
<classPathEntry location="mysql-connector-java-5.1.45-bin.jar"/>

<context id="default" targetRuntime="MyBatis3">
    <property name="beginningDelimiter" value="`"/>
    <property name="endingDelimiter" value="`"/>
    <!-- optional,旨在创建class时,对注释进行控制 -->
    <commentGenerator>
        <property name="suppressDate" value="true"/>
        <!-- This property is used to specify whether MBG will include any coments in the generated code -->
        <property name="suppressAllComments" value="false"/>
    </commentGenerator>

    <!--jdbc的数据库连接 -->
    <!--<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/seq"-->
    <!--userId="root" password="">-->
    <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                    connectionURL="jdbc:mysql://<prod_hostname>:3306/<app_name>?useUnicode=true&amp;characterEncoding=UTF-8"
                    userId="me" password="myPass">
    </jdbcConnection>

    <!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
    <javaTypeResolver>
        <property name="forceBigDecimals" value="false"/>
    </javaTypeResolver>

    <!-- Model模型生成器,用来生成含有主键key的类,记录类 以及查询Example类
        targetPackage     指定生成的model生成所在的包名
        targetProject     指定在该项目下所在的路径-->
    <javaModelGenerator targetPackage="com.johnny.onlinemall.domain" targetProject="../src/main/java">
        <!-- 是否对model添加构造函数 -->
        <property name="constructorBased" value="false"/>

        <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
        <property name="enableSubPackages" value="false"/>

        <!-- 建立的Model对象是否不可改变,即生成的Model对象不会有 setter方法,只有构造方法 -->
        <property name="immutable" value="false"/>

        <!-- 给Model添加一个父类 -->

        <!-- 是否对类CHAR类型的列的数据进行trim操作 -->
        <property name="trimStrings" value="true"/>
    </javaModelGenerator>

    <!--Mapper映射文件生成所在的目录 为每一个数据库的表生成对应的SqlMap文件 -->
    <sqlMapGenerator targetPackage="com.johnny.onlinemall.mapper" targetProject="../src/main/resources">
        <property name="enableSubPackages" value="false"/>
    </sqlMapGenerator>

    <!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码
            type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象
            type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象
            type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口-->
    <javaClientGenerator targetPackage="com.johnny.onlinemall.mapper" targetProject="../src/main/java" type="MIXEDMAPPER">
        <property name="enableSubPackages" value=""/>
        <!-- 定义Maper.java 源代码中的ByExample() 方法的可视性,可选的值有:public;private;protected;default;注意:如果 targetRuntime="MyBatis3",此参数被忽略-->
        <property name="exampleMethodVisibility" value=""/>
<!--方法名计数器 Important note: this property is ignored if the target runtime is MyBatis3. -->
<property name="methodNameCalculator" value=""/>

        <!-- 为生成的接口添加父接口 -->
        <property name="rootInterface" value=""/>

    </javaClientGenerator>

    <!--_column防止字段名和数据库关键字一样-->
    <!--<table tableName="margin_balance"  domainObjectName="MarginBalance"></table>-->
    <!--&lt;!&ndash;防止表名和数据库关键字一样&ndash;&gt;-->
    <!--<property name="runtimeTableName" value="`column`"></property>-->
    <!--&lt;!&ndash;</table>&ndash;&gt;-->
    <!-- optional   , only for mybatis3 runtime
         自动生成的键值(identity,或者序列值)
       如果指定此元素,MBG将会生成<selectKey>元素,然后将此元素插入到SQL Map的<insert> 元素之中
       sqlStatement 的语句将会返回新的值
       如果是一个自增主键的话,你可以使用预定义的语句,或者添加自定义的SQL语句. 预定义的值如下:
          Cloudscape    This will translate to: VALUES IDENTITY_VAL_LOCAL()
          DB2:      VALUES IDENTITY_VAL_LOCAL()
          DB2_MF:       SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1
          Derby:        VALUES IDENTITY_VAL_LOCAL()
          HSQLDB:   CALL IDENTITY()
          Informix:     select dbinfo('sqlca.sqlerrd1') from systables where tabid=1
          MySql:        SELECT LAST_INSERT_ID()
          SqlServer:    SELECT SCOPE_IDENTITY()
          SYBASE:   SELECT @@IDENTITY
          JDBC:     This will configure MBG to generate code for MyBatis3 suport of JDBC standard generated keys. This is a database independent method of obtaining the value from identity columns. identity: 自增主键  If true, then the column is flagged as an identity column and the generated <selectKey> element will be placed after the insert (for an identity column). If false, then the generated <selectKey> will be placed before the insert (typically for a sequence).-->
    <!--<generatedKey column="" sqlStatement="" identity="" type=""/>-->
    <table tableName="trans_log" delimitIdentifiers="true" delimitAllColumns="true"/>
    <!-- optional.
            列的命名规则:
            MBG使用 <columnRenamingRule> 元素在计算列名的对应 名称之前,先对列名进行重命名,
            作用:一般需要对BUSI_CLIENT_NO 前的BUSI_进行过滤,支持正则表达式
         searchString 表示要被换掉的字符串,replaceString 则是要换成的字符串,默认情况下为空字符串,可选 -->
    <!--<columnRenamingRule searchString="" replaceString=""/>-->

    <!-- optional.告诉 MBG 忽略某一列,column,需要忽略的列;delimitedColumnName:true ,匹配column的值和数据库列的名称 大小写完全匹配,false 忽略大小写匹配;是否限定表的列名,即固定表列在Model中的名称-->
    <!--<ignoreColumn column="PLAN_ID" delimitedColumnName="true"/>-->

    <!--optional.覆盖MBG对Model 的生成规则
         column: 数据库的列名
         javaType: 对应的Java数据类型的完全限定名
         在必要的时候可以覆盖由JavaTypeResolver计算得到的java数据类型. For some databases, this is necessary to handle "odd" database types (e.g. MySql's unsigned bigint type should be mapped to java.lang.Object).
         jdbcType:该列的JDBC数据类型(INTEGER, DECIMAL, NUMERIC, VARCHAR, etc.),该列可以覆盖由JavaTypeResolver计算得到的Jdbc类型,对某些数据库而言,对于处理特定的JDBC 驱动癖好 很有必要(e.g. DB2's LONGVARCHAR type should be mapped to VARCHAR for iBATIS).
         typeHandler: -->
    <!--<columnOverride column="" javaType="" jdbcType="" typeHandler="" delimitedColumnName=""/>-->
</context>

generatorConfiguration>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  1. 命令行:mvn mybatis-generator:generate -e,-e参数是为了输出错误信息,方便排查问题。看到“BUILD SUCCESS”表示成功生成。
        

你可能感兴趣的:(mybatis系列总结)