[Mybatis] Mybatis sql映射文件浅析 Mybatis简介(三)

框架与中间件 框架与中间件 8783 人阅读 | 0 人回复

简介

除了配置相关之外,另一个核心就是SQL映射,MyBatis 的真正强大也在于它的映射语句。

Mybatis创建了一套规则以XML为载体映射SQL

之前提到过,各项配置信息将Mybatis应用的整体框架搭建起来,而映射部分则是准备了一次SQL操作所需的信息

一次SQL执行的主要事件是什么?

输入参数解析,绝大多数SQL都是需要参数的

SQL,通过SQL与数据库交互,所以最根本的是SQL,如果连SQL都没有,还扯个蛋蛋?

结果映射,Mybatis可以帮我们完成字段与Java类型的映射

image.png

所以说SQL映射的核心内容为:

  • SQL内容指定
  • 参数信息设置
  • 输出结果设置

当然,每个SQL都需要指定一个ID作为用于执行时的唯一标识符

比如下面示例

<select id="selectPerson"parameterType="int"resultType="hashmap">
  SELECT * FROM PERSON WHERE ID = #{id}
</select>

SELECT * FROM PERSON WHERE ID = #{id} 为SQL内容部分

parameterType="int"以及SQL中的#{id}为参数信息设置部分

resultType="hashmap" 为输出结果设置部分

概况

如上所述,核心内容为:

  • ID
  • SQL内容
  • 入参设置
  • 结果配置

ID用于执行时唯一定位一个映射

对于SQL内容,也没有什么特别的,就是平常所说的数据库可以执行的SQL语句

对于SQL内容中的参数,MyBatis 会通过 JDBC创建一个预处理语句参数

这样的一个参数在 SQL 中会由一个“?”来标识,并被传递到一个新的预处理语句中,类似这样:

// Similar JDBC code, NOT MyBatis…String selectPerson ="SELECT * FROM PERSON WHERE ID=?";PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);

输入的类型使用parameterType进行指定(parameterMap – 已废弃!)

输出信息使用resultMap或者resultType进行指定

从包含的信息的角度分析Mybatis 映射文件的核心内容

如下图所示:

image.png

而对于数据库的CRUD操作,Mybatis的XML配置中分别使用了 insert、select、update、delete四个标签进行分别处理

所以一个映射(映射文件中的一个)常见的形式如下,parameterType以及resultType | resultMap 会根据SQL的类型需要或者不需要

<select | insert | update | delete id="......" parameterType="......" resultType | resultMap="......">

SQL内容......

</select | insert | update | delete>

核心信息为通过Mybatis执行一次SQL的必备信息,Mybatis还可以提供更多的功能设置

所以对于不同类型的SQL,还会有更多的一些配置条目

比如之前提到过的数据库厂商标识符 databaseId,所有类型的SQL映射都可以设置这一属性

而对于其他的附加辅助属性配置,有些是所有类型共同的,而有些是特有的

databaseId就是共有的,比如用于返回自动生成的键的配置useGeneratedKeys 只有insert与update才拥有

文档结构解析

所以从文档结构的形式角度看SQL映射,有四种类型的映射 select、insert、update、delete

每种类型又都有各自的属性设置,有一些是共同的,有一些是特有的

下图如果不清楚,请到评论区中,右键,新标签查看图片,可以查看到大图

image.png

属性角度解析

如果从属性的角度去看待各自的归属,每种属性都有各自的作用功能

他们自身的功能也决定了那些类型才能拥有他

比如键值的返回相关的useGeneratedKeys,就只可能发生在insert或者update中,只有他们才可能自动生成键

image.png

以上为SQL映射文件的核心关键信息以及属性的解读

有些细节还需要注意,关于flushCache以及userCache,前者是是否清空清空本地缓存和二级缓存,后者是本条语句的结果是否进行二级缓存,含义完全不一样

四种类型都有flushCache属性,对于select默认false,对于insert、update、delete默认是true

而userCache只有select有,默认是true

因为缓存机制,比如update 的时候如果 设置flushCache="false",则当你更新后,查询的数据数据还是老的数据。

额外的馈赠-语法糖

在编程实践中,经常有一些公共的方法或者处理逻辑,我们通常将他们提取单独封装,以便提高代码复用程序

那么,对于SQL的编写呢?

Mybatis也提供了封装提取的手段---SQL元素标签

<sql id="xxx">

........

</sql>

然后可以使用include,将他包含到指定的位置

<include refid="xxx"></include>

这是一种静态的织入,通过SQL元素,你可以方便的完成公共SQL片段的提取封装

如果有两个表,都有name、age等字段,我想将他们封装,但是表名却又不一样怎么办?

SQL元素还提供了别名的设置,可以很容易的解决这个问题,请参考官方文档

<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
这个 SQL 片段可以被包含在其他语句中,例如:
<select id="selectUsers"resultType="map">
  select
    <include refid="userColumns"><propertyname="alias"value="t1"/></include>,
    <include refid="userColumns"><propertyname="alias"value="t2"/></include>
  from some_table t1
    cross join some_table t2
</select>

上面示例中包含了两次SQL片段,第一次中alias被替换为t1 ,第二次中的alias被替换为t2,最终的结果形式为:

select
t1.id,
t1.username,
t1.password,
t2.id,
t2.username,
t2.password
from
some_table t1
cross join some_table t2

深入映射

参数(Parameters)细节配置

<selectid="selectPerson"parameterType="int"resultType="hashmap">
  SELECT * FROM PERSON WHERE ID = #{id}
</select>

示例中入参类型通过parameterType指定为int,参数占位符为#{id},这是最简单的一种形式了,入参只是一个Java基本类型(非自定义的对象类型)

对于对象类型Mybatis也可以很好的完成工作,不管是入参时的解析,还是输出结果的映射解析

能够根据属性的名称进行自动的配对

<select id="selectUsers"resultType="User">
  select id, username, password
  from users
  where id = #{id}
</select>
<insert id="insertUser"parameterType="User">
  insert into users (id, username, password)
  values (#{id}, #{username}, #{password})
</insert>

不仅仅支持对象,而且还支持map,当parameterType="map"时,map的key会被用来和占位符中的名称进行匹配

也就是说对于: SELECT * FROM PERSON WHERE ID = #{id} ,当parameterType="map"时,你的参数map需要存在 key=id 的元素

parameterType也支持list,当parameterType="list"时,可以借助于动态SQL的foreach 进行循环

如果是基本数据类型的List,比如List<Integer> 那么直接循环即可;如果是List<User>,可以通过遍历每个元素,然后通过#{item.username}、#{item.password}的形式进行读取

<insert id="..." parameterType="List">
INSERT INTO xxx_table(
username,
password,
createTime
)
values
<foreach collection="list" item="item" index="index" separator=",">
(
#{item.username},
#{item.password},
#{item.createTime}
)
</foreach>
</insert>

可以看得出来,类型的形式很丰富,Mybatis很多时候都可以自动处理,但是你可以对他进行显式的明确指明,比如

#{property,javaType=int,jdbcType=NUMERIC}

property表示字段名称,javaType为int,jdbcType为NUMERIC

(jdbcType是JDBC对于数据库类型的抽象定义,详见java.sql.JDBCType 或者java.sql.Types,可以简单认为数据库字段类型

javaType 通常可以由参数对象确定,除非该对象是一个 HashMap,是map的时候通常也可以很好的工作,但是建议在入参类型是Map对他进行明确的指定

需要注意的是:如果一个列允许 null 值,并且会传递值 null 的参数,就必须要指定 JDBC Type

当你在插入时,如果需要使用自定义的typeHandler ,也应该在此处进行指定

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

对于数值类型,还可以设置保留小数的位数

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

对于参数的细化配置也很容易理解,他要么是用于使用时确定入参或者数据库字段的具体类型,如javaType或者jdbcType

要么就是在字段处理过程中增加的一些处理所需要的信息,比如是不是需要按照自定义处理器处理后在执行到数据库?是不是将数值的小数位数处理后在去执行数据库?

另外对于存储过程的调用Mybatis也是有支持的,mode 属性允许你指定 IN,OUT 或 INOUT 参数。

通常我们使用 #{}的格式进行字符串处理,这样可以安全,是通常的首选,但是如果你就是想直接插入一个字符串到SQL中,可以使用,不过很显然,,不过很显然,使用时 你要非常慎重

ResultMap-别名映射

Mybatis好用的一大神器就是ResultMap,可以让你高效灵活的从结果集映射到你想要的类型中,能够进行很多高级的映射

 一般的映射可以借助于resultType就可以解决了,resultType后面的值同parameterType类似

parameterType resultType的值都用于明确类型,可以使用完全限定名

不过你是否还记得入门简介中关于typeAlias中的介绍?

Mybatis内置了Java基础类型的别名,你都可以直接使用

借助于resultType可以完成一些基本的诉求,比如从单表到对应实体类对象的映射,能够自动的根据字段名称和属性名称进行匹配

image.png

但是如果名称不对应又该怎么办?

如果你的实体中的属性名称为userName,数据库字段名为name,Mybatis真的敢擅自的将这两者对应起来么?

如下图所示,将之前的第一个示例稍作修改,增加一个StudentAnother,name更改为了userName,并将测试代码稍作修改

从结果可以看得到,实体中的userName是null ,Mybatis肯定不敢擅自映射

image.png

一种可行的方式是使用别名,通过数据库字段AS设置别名,就可以成功的完成映射

image.png

通过别名,将数据库列名通过别名与属性字段建立映射关系,然后Mybatis就可以进行自动匹配了

但是这种形式如果有多条SQL,每个SQL中都需要有别名,而且,如果后续有原因修改对象的字段名字,怎么办?

本文作者:程序员潇然 疯狂的字节X https://crazybytex.com/

另外的方式就是使用ResultMap,ResultMap的基础用法就是相当于设置别名

但是借助于ResultMap,将别名的映射关系,维护在ResultMap中,所有使用到此映射类型的SQL都只需要关联这个ResultMap即可,如果有变更,仅仅需要变更ResultMap中的属性字段对应关系

所有的SQL中的内容并不需要变动

如下图所示,SQL中字段与实体类中不匹配,查询的结果为null

右侧通过ResultMap将userName与列名name进行了映射,就可以成功读取数据

image.png

ResultMap最基础的形式如下

<resultMap id="............" type=".................">
<id property="............" column="............"/>
<result property="............" column="............"/>
</resultMap>

ResultMap需要id和type,id用于唯一标识符,type用于指明类型,比如Blog

ResultMap最基础的两个信息是id和result元素

他们的内容均为property="......." column="...........",property(对象的属性字段)和clumn(数据库的列名)

对于基础性的映射借助于id和result就可以完全搞定, id 表示的结果将是对象的标识属性,可以认为对象的唯一标识符用id指定,这对于性能的提高很有作用

小结

对于ResultMap就是做字段到属性的映射,id和result都是这个作用,但是如果是唯一标识符请使用id来指定

另外对于每一个字段,还可以明确的声明javaType和jdbcType,以及typeHandler用于更加细致的解析映射

所以说基本元素为:

image.png

ResultMap-高级映射

ResultMap当然不仅仅是像上面那样只是别名的转换,还可以进行更加复杂的映射

对于结果集返回有哪些场景?

“将一行记录映射为一个对象”与“将多行记录映射为对象列表”这两者本质是一样的,因为所需要做的映射是一样的

比如上面数据库列名name到字段userName 的映射,不管是一行记录还是多行记录,他们都是一样的

所以下面就以一个对象为例

单纯的映射

比如上面的例子,数据库列名与实体类中的字段一一对应(尽管名称不完全匹配,但是仍旧是一一对应的)

组合的映射

对于关系型数据库存在着关联关系的说法,一对一,一对多等

这些关联关系最终也是要映射到对象中的, 所以对象中经常也会存在多种对应关系

比如下面官方文档中的示例----查询博客详情

一个博客Blog 对应着一个作者Author ,一个作者可能有多个博文Post,每篇博文有零或多条的评论Post_Tag 和标签Tag

image.png

<!-- Very Complex Statement -->
<selectid="selectBlogDetails"resultMap="detailedBlogResultMap">
  select
       B.id as blog_id,
       B.title as blog_title,
       B.author_id as blog_author_id,
       A.id as author_id,
       A.username as author_username,
       A.password as author_password,
       A.email as author_email,
       A.bio as author_bio,
       A.favourite_section as author_favourite_section,
       P.id as post_id,
       P.blog_id as post_blog_id,
       P.author_id as post_author_id,
       P.created_on as post_created_on,
       P.section as post_section,
       P.subject as post_subject,
       P.draft as draft,
       P.body as post_body,
       C.id as comment_id,
       C.post_id as comment_post_id,
       C.name as comment_name,
       C.comment as comment_text,
       T.id as tag_id,
       T.name as tag_name
  from Blog B
       left outer join Author A on B.author_id = A.id
       left outer join Post P on B.id = P.blog_id
       left outer join Comment C on P.id = C.post_id
       left outer join Post_Tag PT on PT.post_id = P.id
       left outer join Tag T on PT.tag_id = T.id
  where B.id = #{id}
</select>

对于实体类,一种可能的形式如下

Blog中有一个Author,有一个List <Post> ,每一个Post中又有List <Comment> 和 List <Tag>

image.png

可以看得出来对于组合映射又有一对一以及一对多两种形式

(尽管Blog存在List<Post> postList; 但是在Mybatis中使用时,对于关系是从紧邻的上一层确定的,比如对于Comment看Post,对于Post看Blog,而不是从Blog看Comment )

Mybatis的ResultMap可以完成类似上述SQL与实体类的映射

在Mybatis中只有两种情况,一对一和一对多

一对一Association

对于一对一被称作关联,在ResultMap中使用association元素表示这种关系

含义为:

association中的所有的字段 映射为association元素上property指定的一个属性

比如下面示例,将id和username 映射为author,谁的author?他的直接外层是谁就是谁!

<association property="author"column="blog_author_id"javaType="Author">
<id property="id"column="author_id"/>
<result property="username"column="author_username"/>

</association>

对于association的基本格式如下,相当于在基础的ResultMap中插入了一个“一对一”的对应

<resultMap id="............" type=".................">
<id property="............" column="............"/>
<result property="............" column="............"/>
<association property="............" column="............" javaType="............">
<id property="............" column="............"/>
<result property="............" column="............"/>

</association>

</resultMap>

association中对于字段和属性的映射也是使用id和result,对于唯一标志使用id来表示

关联的嵌套查询

对于一个association还可以对他进行嵌套查询,也就是在查询中进行查询

比如官方示例中

<resultMap id="blogResult"type="Blog">
<association property="author"column="author_id"javaType="Author"select="selectAuthor"/>
</resultMap>

<select id="selectBlog"resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<selectid="selectAuthor"resultType="Author">
  SELECT * FROM AUTHOR WHERE ID = #{id}
</select>

当执行selectBlog时,会执行 SELECT * FROM BLOG WHERE ID = #{id} ,查询得到的结果映射到blogResult,在这个ResultMap中使用了association元素

这个association元素使用select标签进行了嵌套查询,也就是使用另外的一个映射selectAuthor进行处理

处理流程:

  1. 先查询selectBlog查询所有的结果
  2. 对于每一条结果,然后又再一次的select,这就是嵌套查询

这会出现“N+1 查询问题”,查询一次SQL查询出一个列表(这是1)然后对于这个列表的每一个结果都再次的查询(这是N)性能有些时候很不好

嵌套查询使用select,还有一个重要的就是association 上的 column,这个column用于指定嵌套查询的参数

比如上面的例子,将会使用author_id传递给 SELECT * FROM AUTHOR WHERE ID = #{id}中的id,然后进行查询

此处仅仅只是一个参数,如果是多个参数仍旧可以,使用 column= ” {prop1=col1,prop2=col2} ”的形式

比如:

image.png

上面就是通过column指定将要传递给嵌套内查询的参数

鉴于ResultMap可以提供很好地映射,所以上面的示例完全可以修改为普通的association形式,通过join将关联查询的结果映射到指定的对象中,而不是借助于select元素进行嵌套查询

一对多collection

对于一对多关系,Mybatis使用collection

collection的逻辑本质上与association是一样的,都是对象字段映射

只不过用于区分,也用于在除了数据时,具体的指定类型

一个collection形式为:

<collection property="posts"ofType="domain.blog.Post">
<id property="id"column="post_id"/>
<result property="subject"column="post_subject"/>
<result property="body"column="post_body"/>
</collection>

内部依然是使用id和result完成字段和属性的映射

但是collection上使用ofType来指定这个属性的类型,而不是之前的javaType

这也很好理解,对于一对一或者检查的查询,他就是一个对象类型,所以使用JavaType

对于集合的映射,我们很清楚的知道他是一个集合,所以集合类型是他的javaType,比如 javaType="ArrayList",Mybatis 在很多情况下会为你算出来,所以可以省略javaType

但是,什么类型的集合?还需要说明,所以使用ofType进行指定,看起来更加清晰

使用collection的基础形式为:

<resultMap id="............" type=".................">
<id property="............" column="............"/>
<result property="............" column="............"/>


<collection property="............" column="............" ofType="............">
<id property="............" column="............"/>
<result property="............" column="............"/>
</collection>

</resultMap>

集合的嵌套查询

对于collection也可以采用类似association中的select元素进行嵌套查询

原理也是类似,当检索出来结果后,借助于select指定的查询语句,循环查询

<resultMap id="blogResult"type="Blog">
<collection property="posts"javaType="ArrayList"column="id"ofType="Post"select="selectPostsForBlog"/>
</resultMap>
<select id="selectBlog"resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<selectid="selectPostsForBlog"resultType="Post">
  SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>

ResultMap的嵌套

在前面的叙述中,所有的内部的关联或者集合的属性映射都是直接嵌套在外部ResultMap中的

image.png

借助于嵌套查询的形式 select属性,可以进行嵌套查询,通过嵌套查询的方式,相当于经过这个select,内部的字段映射部分被路由到另一个ResultMap(ResultType)中了

而不需要在这个ResultMap中逐个重新的进行字段的映射指定

但是select会有1+N的问题,但是使用select时这种使用外部ResultMap(resultType)的形式却是很有实用意义

因为如果可以进行分离,被剥离的那一部分既可以单独使用,又可以嵌套在其他的ResultMap中,组合成更加强大的形式

本文作者:程序员潇然 疯狂的字节X https://crazybytex.com/

Mybatis是支持ResultMap嵌套的

image.png

不仅仅association支持ResultMap的嵌套,collection也是支持的

image.png

可以看得出来,不管是借助于select的嵌套查询,还是ResultMap的嵌套,都只是在association上或者collection上附加select或者resultMap属性即可

然后就可以省略掉标签内部的字段映射处理了(id和result)

除非开发前对ResultMap的层级结构进行过统一设计布局,否则,内嵌其他人开发的ResultMap,也并不一定总是好事,当内嵌的ResultMap发生变动时,某些情况可能会导致问题

嵌套的ResultMap一定需要是本文件中的吗?当然不是必须的,比如下面示例中借助于:接口的全限定名称进行索引

<association property="courseEntity" column="course_id"
javaType="com.xxx.xxx.domain.CourseEntity" resultMap="com.xxx.xxx.dao.CourseMapper.courseResultMap">
</association>

ResultMap的重用

ResultMap的嵌套也是一种复用,此处说的重用非解耦后的复用

在ResultMap中,我们通过id或者result 将数据库字段和实体类中的属性名进行对应

列名和属性名的对应,以及列名和属性名全部都是固定的了,如下图所示,username就是和author_username对应

image.png

在之前的例子中,一个blog有一个作者,但是如果一个博客还有一个联合作者怎么办?就像很多书可能不仅仅只有一个作者

在这种场景下:有两个作者,他们的java类型必然都是Author

而且他们的字段也是相同的,但是你不得不将他们进行区分,如下面SQL中所示,关联了两次Author表,通过前缀进行了区分

一种解决方法就是将映射部分也重写两次,就像关联两次那样,仅仅是列名column前缀不同(可以将这两个ResultMap嵌入到blogResult中或者内容移入到外层ResultMap中,总之是写两遍映射)

image.png

还有一种方法就是借助于columnPrefix,如下图所示,Blog中有两个Author的实例,一个是author另一个是coAuthor,关联关系,使用association

他们都是Author类的实例,所以使用同样的ResultMap,通过columnPrefix对其中一个映射添加列前缀

通过这个列前缀,就相当于有了另外的一个ResultMap,这个ResultMap就是指定的ResultMap中的column中每一个值都加上一个前缀

image.png

构造方法字段值注入

使用Mybatis的核心就是为了执行SQL以及完成结果映射,结果的映射必然要创建最终需要映射的结果的对象

通过ResultMap中的id和result指定的字段值都是通过setter设置器方法进行值的设置的

既然最终就是要创建一个指定类型并且具有指定属性的对象结果,那么为什么一定非得是通过setter,难道不能在创建对象的时候通过构造方法初始化对象吗?

Mybatis的ResultMap是支持构造方法设置的

对于构造方法的属性值设置,通过constructor进行

将之前的例子稍作修改,增加一个构造方法,复制一个ResultMap,添加constructor,就可以完成映射

image.png

借助于constructor与使用id和result映射在业务逻辑上没有什么本质的区别,都是将列名与字段进行映射,变的是形式

因为是借助于构造函数,所以constructor中与ResultMap中的其他字段映射是有区别的,不是使用id和result 使用的是 arg 参数

简言之,使用构造方法需要根据方法签名进行匹配,方法签名就是类型和个数的匹配,所以需要javaType

对于有些场景你可能不希望暴露某些属性的共有setter设置器,就可以使用构造方法的形式

上面的示例中没有通过constructor对id进行映射,如果对id进行映射需要使用 <idArg column="id" javaType="int"/>(没写错 就是idArg )

对于使用constructor对值进行解析映射,根本就是匹配正确的构造方法,除了使用javaType还有name,通过name指定构造方法参数的名称

从版本 3.4.3 开始,如果指定了名称name,就不需要严格死板的按照顺序对应了,可以打乱顺序。

没有人会刻意的打乱顺序,但是永远的保证映射的顺序不变动是很难得

image.png

鉴别器

重新建一个表作为示例,配置信息还是如原来一样,SQL映射文件也是在第一个示例中的XML中编写的

主要的信息如下,表以及数据以及实体类以及映射文件等

image.png

定义了三个类,一个Person类作为抽象模型(尽管我这个不是抽象类)

一个成人类Adult和一个儿童类Child

Adult增加了company属性,Child增加了school属性

image.png

每个类都有setter和getter方法,并且还重写了toString方法

映射文件

image.png

测试类

package third;

import first.StudentAnother;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Test {

    public static void main(String[] args) throws Exception {

        /*
         * 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。
         * SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。
         * 而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。
         * */
        String resource = "config/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"development");
        /*
         * 从 SqlSessionFactory 中获取 SqlSession
         * */
        SqlSession session = sqlSessionFactory.openSession();
        try {
            List<Person> personList = session.selectList("mapper.myMapper.selectPerson");
            personList.stream().forEach(i->{
                System.out.print(i);

                System.out.println(i.getClass().getName());
            });
        } finally {
            session.close();
        }
    }

}

测试结果

image.png

Mybatis很神奇的将结果映射为了不同的子类对象

所以说如果一条记录可能会对应多种不同类型的对象,就可以借助于discriminator,通过某个字段的数据鉴别,映射为不同的类

ResultMap中的type对应了父类型,discriminator上的column对应了需要鉴别的列名

每一个case对应着一种类型或者一个ResultMap,通过discriminator就可以根据鉴别的值的不同进行动态的选择

discriminator可以很轻松的处理者中类层次关系中数据的映射

使用discriminator的结果处理步骤

  • MyBatis将会从结果集中取出每条记录,然后比较它的指定鉴别字段的值。
  • 如果匹配任何discriminator中的case,它将使用由case指定的resultMap(resultType)
  • 如果没有匹配到任何case,MyBatis只是简单的使用定义在discriminator块外面的resultMap

如果将映射关系中case后面的值设置为3和4(数据库中只有1和2)

结果如下,仅仅匹配了discriminator外面的部分

image.png

common_log.png 转载务必注明出处:程序员潇然,疯狂的字节X,https://crazybytex.com/thread-166-1-1.html

关注下面的标签,发现更多相似文章
    黄小斜学Java

    疯狂的字节X

  • 目前专注于分享Java领域干货,公众号同步更新。原创以及收集整理,把最好的留下。
    包括但不限于JVM、计算机科学、算法、数据库、分布式、Spring全家桶、微服务、高并发、Docker容器、ELK、大数据等相关知识,一起进步,一起成长。
热门推荐
海康摄像头接入 wvp-GB28181-pro平台测试验
[md]### 简介 开箱即用的28181协议视频平台 `https://github.c
[CXX1300] CMake '3.18.1' was not
[md][CXX1300] CMake '3.18.1' was not found in SDK, PATH, or
[若依]微服务springcloud版新建增添加一个
[md]若依框架是一个比较出名的后台管理系统,有多个不同版本。