• MyBatis Mapper文件简述


    Java Mapper类

    通过在Java中定义一个和MyBatis中mapper元素命名空间相同的Mapper接口(接口中方法名必须匹配映射语句的ID,返回值类型也必须匹配),可以在Java中方便地使用Mapper。
    通过SQLSession对象的getMapper方法,传入一个Mapper接口的Mapper.class,即可通过返回的Mapper对象调用定义好的SQLMapper方法。
    对于搭配Spring框架的MyBatis,直接使用注解即可获得Mapper对象。
    还可以通过Mapper接口中方法的注解来进行Mapper的直接配置,就可以不使用Mapper XML了。
    使用
    @InsertProvider
    @UpdateProvider
    @DeleteProvider
    @SelectProvider
    注解,搭配MyBatis提供的SQL类,可以在代码中动态拼接SQL语句。

    映射文件顶级元素

    cache – 对给定命名空间的缓存配置。
    cache-ref – 对其他命名空间缓存配置的引用。
    resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
    sql – 可被其他语句引用的可重用语句块。
    insert – 映射插入语句
    update – 映射更新语句
    delete – 映射删除语句
    select – 映射查询语句

    参数填充与字符串替换

    使用#{param}或者#{0}的格式,可以在SQL语句中放置参数,等调用的时候再向里面填充,可以使用#{property,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler,numericScale=2}的形式,指定参数的具体类型、处理器类以及保留的小数位数。在搭配储存过程时,允许指定mode=IN/OUT/INOUT,即数据库输入参数或者输出参数或者输入输出参数。

    ${}是字符串替换拼接,是MyBatis中变量的值的替换,无法防止注入,而#{}是SQL预编译过程中替换为一个?再进行注入,注入的值会带引号。
    表名或者列名作为参数时,必须使用${},order by 时,必须使用${}(否则会多个引号),使用${}时要注意何时加或不加单引号以及注入问题。

    select

    <select
      id="selectPerson"    语句唯一标识符
      parameterType="int"    传入参数的完全限定名或者别名,可以不设置
      resultType="hashmap"    返回期望类型的完全限定名或者别名(对于集合,是集合内部类型而不是集合类型),和resultMap参数二选一
      resultMap="personResultMap"    外部resultMap的命名引用
      flushCache="false"    每次调用语句是否刷新cache
      useCache="true"    本语句结果是否被二级缓存
      timeout="10"    超时时间
      fetchSize="256"    这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等
      statementType="PREPARED"    使用什么的对象操作SQL语句,STATEMENT直接操作SQL,PREPARED预处理编译,CALLABLE执行存储过程
      resultSetType="FORWARD_ONLY"    结果集对象的类型,是否只能获取next还是能进行滚动,滚动时是否对更改敏感
      databaseId="oracle"    数据库厂商标识
      resultOrdered="false"    嵌套结果 select 语句适用,返回的主结果行不会带来对前面结果集的引用,不会导致内存不够用
      resultSets="cls1,cls2">    多结果集,为每个结果集指定一个名字
    

    insert, update 和 delete

    <insert/update/delete
      id="insertAuthor"    SQL语句的ID
      parameterType="domain.blog.Author"    传入参数的类名
      flushCache="true"    语句调用会导致本地缓存和二级缓存清空
      statementType="PREPARED"    SQL执行方式
      keyProperty="id"    (仅对 insert 和 update 有用)使MyBatis取出数据库生成的键并向某个目标属性赋值
      keyColumn=""    (仅对 insert 和 update 有用)通过生成的键值设置的表中的列名,主键不是表中第一列时需要设置
      useGeneratedKeys="true"    (仅对 insert 和 update 有用)使MyBatis取出数据库自动生成的主键
      timeout="20"   抛出异常前的超时时间
      databaseId="oracle">     数据库厂商标识
    

    selectKey标签可以插入在insert标签中,与select标签相比,多了order属性,该属性如果设置为 BEFORE,那么它会首先生成主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 中的语句

    <selectKey
      keyProperty="id"
      resultType="int"
      order="BEFORE"
      statementType="PREPARED">
    

    SQL语句

    可以定义可重用的SQL代码段,例如

    <sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
    <select id="selectUsers" resultType="map">
      select
        <include refid="userColumns"><property name="alias" value="t1"/></include>,
        <include refid="userColumns"><property name="alias" value="t2"/></include>
      from some_table t1
        cross join some_table t2
    </select>
    

    属性值也可以被用在 include 元素的 refid 属性里或 include 元素的内部语句中,如<include refid="${include_target}"/>,可能因为${}是在XML解析时进行字符串拼接替换。

    resultMap结果映射

    resultMap 元素是 MyBatis 中最重要最强大的元素。它可以将从数据库中获取的复杂对象直接映射为Java中的对象。
    如下,即为使用resultType将数据库中的结果直接映射为类对象,如果数据库中的列名与类属性名没有完全匹配,那么可以使用as来匹配:

    <!-- mybatis-config.xml 中 -->
    <typeAlias type="com.someapp.model.User" alias="User"/>
    
    <!-- SQL 映射 XML 中 -->
    <select id="selectUsers" resultType="User">
      select id, 
        user_name           as "userName",
        hashed_password     as "hashedPassword"
      from some_table
      where id = #{id}
    </select>
    

    数据库结果与类的不匹配,除了上面简单的方式,还可以通过resultMap中的id和result参数进行绑定。
    resultMap标签还能对一对一和一对多结果进行关系映射。

    resultMap高级结果映射

    resultMap标签可以配置许多属性子标签:

    • constructor - 用于在实例化类时,注入结果到构造方法中
      • idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
      • arg - 将被注入到构造方法的一个普通结果
    • id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
    • result – 注入到字段或 JavaBean 属性的普通结果
    • association – 一个复杂类型的关联;许多结果将包装成这种类型
      • 嵌套结果映射 – 关联本身可以是一个 resultMap 元素,或者从别处引用一个
    • collection – 一个复杂类型的集合
      • 嵌套结果映射 – 集合本身可以是一个 resultMap 元素,或者从别处引用一个
    • discriminator – 使用结果值来决定使用哪个 resultMap
      • case – 基于某些值的结果映射
        • 嵌套结果映射 – case 本身可以是一个 resultMap 元素,因此可以具有相同的结构和元素,或者从别处引用一个

    id & result

    这两个标签功能一致,但是id时对象的标识属性,在比较实例是否相等时用到,可以提高整体性能,尤其是进行缓存和嵌套结果映射时。
    这两个标签有5个属性:

    • property 映射到Java对象属性的字段或属性。支持用点限定具体的属性,如“address.street.number”
    • column 数据库中的列名,或者是列的别名。
    • javaType 希望映射到的Java类的完全限定名,或一个类型别名
    • jdbcType 属性对应的JDBC 类型
    • typeHandler 针对这个属性使用的类型处理器

    constructor

    当创建数据库结果映射到的Java对象时,可能需要进行一些初始化处理,该标签就是映射到类的构造方法的形参。
    该标签下的idArg标签与arg标签的区别和id以及result标签的区别类似。
    该标签下的属性有column,javaType,jdbcType,typeHandler,与其他标签类似。
    该标签下有select属性,用于加载复杂类型属性的映射语句的 ID,它会从 column 属性中指定的列检索数据,作为参数传递给此 select 语句。还有resultMap,可以将嵌套的结果集映射到一个合适的对象树中,可以替代select语句。
    该标签下有name属性,是Java对象构造方法的名字,搭配@Param注解可以乱序传参,否则该标签内的参数顺序和构造方法参数顺序必须一致。

    association

    关联,数据库关系中处理“有一个”类型的关系。如一个订单对应一个用户。属性有property,javaType,jdbcType和typeHandler。子标签有id和result两种。

    关联的嵌套查询

    select(resultMap)->resultMap->association(select)
    该association标签有select属性,可以指定一个select标签对象,进行一对一的级联查询。
    该标签具有fetchType属性,可以指定为lazy或eager,即关联对象是懒加载还是积极加载。
    使用该标签的查询叫做嵌套查询,存在N+1查询的问题,即对母查询的每个结果再进行一次子查询,会带来极大的性能问题,使用lazy的加载查询模式可以缓解这个问题,但是还有使用嵌套结果的方法来解决这个问题。

    关联的嵌套结果映射

    select(resultMap)->resultMap->association(resultMap)
    使用association标签的resultMap属性,可以进行结果的级联,即在数据库端,使用join的方法,将表联合在一起,查询到关联了两个表的结果,然后使用association指定两个表的关系,把子表添加到association的resultMap中,MyBatis就会按照这个关系,将两个表的对象进行关联,并返回结果。
    在使用这种方式关联时,如果有多个相同的表被关联,就会产生重名的问题,比如一个文章有一个作者还有一个共同作者,而两个作者的表是一模一样的,这是可以使用columnPrefix="co_"属性指定某个表的前缀,以此进行区分。
    如果被关联的子对象有空属性,默认为至少有一个属性不为空才会创建子对象,但可以使用notNullColumn=""属性指定当某列(多个列用,隔开)不为空时才创建子对象。

    resultSets关联的多结果集

    这是N+1查询问题的另一种解决办法。也就是在数据库端执行储存过程,在过程中获得多个结果,然后把结果集一次性地返回到服务器。
    select{call XXXXXX}(resultSets,resultMap)->resultMap->association(resultSet,column,foreignColumn)
    在select语句中通过resultSets属性指定返回的结果集的每个结果,然后在resultMap属性中指定处理的结果集;再在resultMap的association中,设置resultSet为select->resultSets中的某一个,column为结果集中与该子查询相匹配的列, foreignColumn为子结果中与父结果中的外键,通过这几个参数,将储存过程返回的结果匹配到结果中(因为储存结果返回的值并未建立表之间的关联关系)。

    collection

    collection与association非常相似,与其不同的点是association是“有一个”,collection是对应多个。其对应的javaType经常为ArrayList之类的,然后通过ofType属性指定在集合中具体的类。
    collection的嵌套查询,嵌套结果和多结果集查询与association基本一致,只是多了一个ofType的参数。

    discriminator 鉴别器

    储存结果可能能返回多个种类的值,需要根据一定的值判断到底是那个种类的结果。

    <discriminator javaType="int" column="draft">
      <case value="1" resultType="DraftPost"/>
    </discriminator>
    

    以上就表示判断结果集中的draft列,然后根据这一列的值与哪个case的value值相等,然后使用后面的resultType匹配查询结果。
    每个case之间是互斥的,也就是一个鉴别器只能匹配出一个结果,其他返回结果都将被忽略。鉴别器的匹配结果也可能是空的。
    鉴别器与switch语句很像,switch中可以调整break的位置来执行多个case,而鉴别器中也可以通过匹配项指定的resultMap的extends属性来匹配更多的case。

    自动映射

    Mybatis会将SQL查询结果与Java中的对象相匹配,然后将查询结果赋值,如果没有在resultMap中将列与属性绑定,那么MyBatis就会自动将其映射。
    MyBaits的映射规则为忽略列与对象属性的大小写,名字相同就匹配赋值,SQL的下划线命名与Java的驼峰命名法的自动映射需要在MyBatis设置中将mapUnderscoreToCamelCase设置为true。
    自动映射有三个等级,NONE 为不自动映射,仅使用手动映射;PARTIAL 为对除在内部定义了嵌套结果映射(也就是连接的属性)以外的属性进行映射;FULL - 自动映射所有属性(可能会带来嵌套结果中重复的ID等列出现非期望的映射的问题)。
    可以在resultMap中设置autoMapping="false"来禁用这个结果集的自动映射。

    缓存

    MyBatis默认开启了本地的,仅对一个会话的缓存,要启用全局会话的二级缓存,需要在SQL Mapper文件中添加<cache />标签,缓存只作用于 cache 标签所在的映射文件中的语句。
    缓存默认有以下规则:

    • 映射语句文件中的所有 select 语句的结果将会被缓存。
    • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
    • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
    • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
    • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
    • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
      cache标签有以下参数:
    <cache
      eviction="FIFO"    可选LRU,FIFO,SOFT,WEAK四种
      flushInterval="60000"    自动刷新间隔
      size="512"    一个缓存对象的最多引用数目
      readOnly="true"/>    缓存默认是基于事务,可读/写的,如果开启readOnly那么会带来性能上的提升,但是不可写。
    

    自定义缓存

    需要实现Cache接口,然后在cache标签的type属性指定接口的实现类。可以通过在实现类中添加Java Bean属性,然后用cache的property子标签传值的方法,向实现类传递配置值,比如定义cache文件位置等。
    可以在缓存实现类中实现InitializingObject 接口,来在读取配置文件后进行一些初始化操作。

    cache配置引用

    通过这样的方式,可以将另一个Mapper命名空间中的cache配置引用到当前配置空间。

  • 相关阅读:
    EL表达式
    单例模式
    标准标签JSTL
    五大常用算法之三:贪心算法
    python字符串处理
    判断视图存不存在
    判断插入的数据在表中存不存在
    sql因为发现对象名称 'dbo.Ct2' 和索引名称 'PK_Ct2' 有重复的键,所以ALTER TABLE ALTER COLUMN 。。。 失败。
    C# MD5算法 16 32 大小写
    制作VS2022中文离线安装包
  • 原文地址:https://www.cnblogs.com/CoveredWithDust/p/MyBatis_Mapper.html
Copyright © 2020-2023  润新知