返回顶部
首页 > 资讯 > 后端开发 > Python >MyBatisdiscriminator标签原理实例解析
  • 883
分享到

MyBatisdiscriminator标签原理实例解析

MyBatisdiscriminator标签MyBatisdiscriminator 2023-02-05 15:02:06 883人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录一、什么业务情况会使用discriminator标签?二、discriminator使用Mapper接口配置测试三、discriminator原理Discriminator对象结

一、什么业务情况会使用discriminator标签?

假设我们有一张user表:

使用查询语句select * from user有如下需求

当用户年龄为18岁时查询结果显示生日信息。

当用户年龄不为18岁时查询结果不显示生日信息。(显示为空或NULL即可)

如果我们使用mybatis,第一个想到的解决办法可能是在Java程序里把用户信息查出来,然后再根据年龄做if判断。但是这样做有点繁琐。还好mybatis提供了一个标签(<discriminator/>)来解决如上的业务需求。discriminator也就是侦察器、也叫鉴别器

二、discriminator使用

还是结合第一节的业务问题来使用discriminator标签

映射文件配置

mapper.xml配置内容如下

<resultMap id="userMapForTestDiscriminator" type="user" autoMapping="false">
    <!--关闭自动映射,那么没有指定的列名不会出现在结果集中-->
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="age" column="age"/>
    <discriminator javaType="int" column="age">
        <case value="18" resultType="user">
            <result property="birthday" column="birthday"/>
        </case>
    </discriminator>
</resultMap>
<select id="selectDiscriminator" resultMap="userMapForTestDiscriminator">
    select * from user limit 2
</select>

select标签的id为selectDiscriminator,并且返回结果集使用resultMap来接收。重点就在resultMap里配置了discriminator。先来解释一下discriminator的作用:

discriminator有个子标签是case,并且指定侦察器鉴别的属性为age。(它的用法很类似于Java中的switch)

当查询的结果集中age列数据等于case指定的value值时(在这个例子里就是当结果集中age列为18时)。则把case标签中的result标签加入到外部的resultMap标签中。反之——如果结果集中的age列值不为18,则不做任何操作。

换个更直观的说法来看。

  • 当结果集中的age列等于18时(本例中)实际上返回的resultMap标签相当于
<resultMap id="userMapForTestDiscriminator" type="user" autoMapping="false">
    <!--关闭自动映射,那么没有指定的列名不会出现在结果集中-->
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="age" column="age"/>
    <result property="birthday" column="birthday"/>
</resultMap>
  • 当结果集中的age列不等于18时(本例中)实际上返回的resultMap标签相当于
<resultMap id="userMapForTestDiscriminator" type="user" autoMapping="false">
    <!--关闭自动映射,那么没有指定的列名不会出现在结果集中-->
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <result property="age" column="age"/>
</resultMap>

怎么样?是不是和Java中的Switch用法一模一样,当满足条件时就执行case语句中的代码。

Mapper接口配置

public interface UserMapper {
  List<User> selectDiscriminator();
}

测试

@Test
public void test1() throws Exception {
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = userMapper.selectDiscriminator();
    for (Object user : users) {
        System.out.println(user);
    }
}

输出结果:User(id=1, username=0.620544543088072, age=18, passWord=222, birthday=2002-10-27, author=null)
User(id=3, username=0.620544543088072, age=22, password=null, birthday=null, author=null)

从输出结果中已经可以看到,当age不等于18的时候,birthdary字段没有值。那么mybatis是如何实现这个功能的呢?下面来从源码角度分析下。

总结

discriminator相当于Java中的Switch,作用是可以动态的控制resultMap标签中的result标签。

三、discriminator原理

mybatis初始化的时候会加载映射配置文件。

  • 把所有的XxxMapper.xml文件解析为MappedStatement对象保存在Configuration对象中。以便于后续的调用。
  • 而每个XxxMapper.xml中的resultMap标签都会被解析为ResultMap对象存储在MappedStatement对象当中
  • ResultMap标签中的每个discriminator标签都会被解析为Discriminator对象存储在ResultMap对象当中。

至此,Discriminator所在的层级就是:

下面就从源码的两个方面揭开discriminator的面纱。

初始化时——加载配置文件并把discriminator标签解析为Discriminator对象存储到内存中。

执行SQL时——如果检测到有与该SQL匹配的Discriminator对象,则调用Discriminator对象的逻辑

Discriminator对象结构

public class Discriminator {
  private ResultMapping resultMapping;
  private Map<String, String> discriminatORMap;
}

Discriminator对象有两个字段

  • resultMapping记录的是<discriminator javaType="int" column="age">中的age字段的相关信息(列名、jdbc类型、Java类型、是否嵌套等等。总之记录的是鉴别器鉴别的那个列的列信息。而这个信息被封装成了ResultMapping对象,比较简单感兴趣的可以看下ResultMapping对象源码)
  • discriminatorMap记录的是<case value="18" resultType="user">case标签的信息。它是一个map结构,key是case中value属性的值,value是resultmap的的唯一标识。(mybatis会通过resultMap的唯一标识去configuration对象中寻找对应的resultMap)

初始化

看到这里,默认读者有看过一定的mybatis源码。mybatis在启动时通过XMLMapperBuilder来加载映射文件(xml文件)。其中包含了对ResultMap标签的解析过程。具体逻辑在XMLMapperBuilder#resultMapElement方法中。代码如下(只列出了有关Discriminator的逻辑)

private ResultMap resultMapElement(Xnode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) {
    // 1. 解析配置文件的标签创建为Discriminator对象
    Discriminator discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
    // 2. 构建ResultMapResolver对象,再调用resolve方法创建ResultMap对象,Discriminator就是在resolve方法中被ResultMap对象中的
    // 说白了是构建ResultMap的辅助类。
    ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
    return resultMapResolver.resolve();
}

调用processDiscriminatorElement方法为Discriminator对象设置详细的属性。

private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) {
  // 通过 column javaType jdbcType typeHandler javaTypeClass typeHandlerClass 
  // 来构造Discriminator对象中的resultMapping字段
  String column = context.getStringAttribute("column");
  String javaType = context.getStringAttribute("javaType");
  String jdbcType = context.getStringAttribute("jdbcType");
  String typeHandler = context.getStringAttribute("typeHandler");
  Class<?> javaTypeClass = resolveClass(javaType);
  Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
  JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
  Map<String, String> discriminatorMap = new HashMap<>();
  // 遍历discriminator标签,把case节点的信息封装为Discriminator对象中的discriminatorMap字段
  for (XNode caseChild : context.getChildren()) {
    String value = caseChild.getStringAttribute("value");
    String resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings, resultType));
    discriminatorMap.put(value, resultMap);
  }
  // 调用辅助类整整的构建Discriminator对象
  return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
}

至此,Discriminator对象就被完整的创建出来了。它会被添加在ResultMap对象中缓存。后续程序执行过程中,就能通过Configuration对象获取MappedStatement对象,再通过MappedStatement对象获取ResultMap对象,再通过ResultMap对象就可以获取Discriminator对象啦!

需要注意的是,每个case标签都会被解析为一个结果集间接存入到configuration对象中。

执行SQL时

在程序通过mybatis执行数据库操作时,会通过ResultSetHandler对象来处理数据库返回的结果集。ResultSetHandler是mybatis的几个核心对象之一。它在DefaultResultSetHandler#resolveDiscriminatedResultMap方法中进行对Discriminator的逻辑处理。方法代码如下

public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {
  // 1 通过resultMap获取鉴别器对象Discriminator
  Discriminator discriminator = resultMap.getDiscriminator();
  while (discriminator != null) {
    // 2. 从鉴别器中获取结果集中对应的需要被鉴别的值。拿文章开头的业务举例,在此就是获取结果集中的age列的值,第一行age的值是18。也就是value的值为18。第二行age的值为22
    final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);
    final String discriminatedMapid = discriminator.getMapIdFor(String.valueOf(value));
    // 3. 判断configuration对象中是否有指定的resultMap对象,后面会根据这个resultMap进行映射结果集
    if (configuration.hasResultMap(discriminatedMapId)) {
      resultMap = configuration.getResultMap(discriminatedMapId);
    }
  }
  return resultMap;
}

代码逻辑的大致步骤如下

  • 通过resultMap获取鉴别器对象Discriminator
  • 从鉴别器中获取结果集中对应的需要被鉴别的值。拿文章开头的业务举例,在此就是获取结果集中的age列的值,第一行age的值是18。也就是value的值为18。第二行age的值为22
  • 获取case中的值,在本例中case会拿age的值和18做比较,如果比较不相等则不做处理,否则会把对应的resultMap的值返回,交给ResultSetHandler去处理映射关系。

以上就是MyBatis discriminator标签原理实例解析的详细内容,更多关于MyBatis discriminator标签的资料请关注编程网其它相关文章!

--结束END--

本文标题: MyBatisdiscriminator标签原理实例解析

本文链接: https://lsjlt.com/news/194242.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • MyBatisdiscriminator标签原理实例解析
    目录一、什么业务情况会使用discriminator标签?二、discriminator使用Mapper接口配置测试三、discriminator原理Discriminator对象结...
    99+
    2023-02-05
    MyBatis discriminator标签 MyBatis discriminator
  • HTML中link标签与a标签实例分析
    本篇内容介绍了“HTML中link标签与a标签实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 首...
    99+
    2024-04-02
  • HTML标签与元素实例分析
    这篇文章主要讲解了“HTML标签与元素实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“HTML标签与元素实例分析”吧!什么是标签标签就是上面这些<...
    99+
    2024-04-02
  • gosyncOnce实现原理示例解析
    目录正文Once 的实现使用示例Once 的一些工作机制Once 详解hotpathatomic.LoadUint32atomic.StoreUint32Mutex总结正文 在很多...
    99+
    2023-01-03
    go sync Once实现原理 go sync.Once
  • mysql游标的原理与用法实例分析
    本文实例讲述了mysql游标的原理与用法。分享给大家供大家参考,具体如下: 本文内容: 什么是游标 创建游标 使用游标 首发日期:2018-04-18 什么是游标: 如果你前面看过mysql...
    99+
    2022-05-12
    mysql 游标
  • HTML的div标签使用实例分析
    本篇内容介绍了“HTML的div标签使用实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! &nbs...
    99+
    2024-04-02
  • HTML常用标签实例代码分析
    这篇文章主要介绍“HTML常用标签实例代码分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“HTML常用标签实例代码分析”文章能帮助大家解决问题。 html常用标...
    99+
    2024-04-02
  • web理论和HTML标签的示例分析
    这篇文章给大家分享的是有关web理论和HTML标签的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。   1,什么是web?   web是运行在internet上最流行...
    99+
    2024-04-02
  • Flask接口签名sign原理与实例代码浅析
    目录作用原理问题问题1解决办法问题2解决办法代码觉得废话多的话,可以直接看代码 作用 防止有人不停的刷接口,对接口作限制 比如说,登录接口,按道理说,应该只有app会请求这个接口 但...
    99+
    2023-02-11
    Flask接口签名sign Flask接口签名
  • HTML5标签与HTML标签的区别示例分析
    这篇“HTML5标签与HTML标签的区别示例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这...
    99+
    2024-04-02
  • HTML5标签的示例分析
    这篇文章给大家分享的是有关HTML5标签的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。可以进行省略的标签不允许写结束标记的标签:area(定义图像映射中的区域)、bas...
    99+
    2024-04-02
  • HTML标签的示例分析
    这篇文章主要为大家展示了“HTML标签的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“HTML标签的示例分析”这篇文章吧。   结构   <html...
    99+
    2024-04-02
  • Instagram标签的示例分析
    这篇文章将为大家详细讲解有关Instagram标签的示例分析,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。人们很容易忽视一些看似无足轻重的小标签,正如Instagram标签的重要性是让人着迷...
    99+
    2023-06-04
  • 解析Android AIDL的实例与原理
    目录一、概述二、创建 .aidl 文件三、生成 .java 文件四、传输复杂数据五、建立 service六、获取服务七、分析调用过程一、概述 简单来说,AIDL 就是定义一个接口,客...
    99+
    2024-04-02
  • JavaLambda表达式实例解析原理
    目录1、实例解析2、InvokeDynamic2.1 方法调用2.2 指令规范2.3 执行过程2.4 MethodHandle1、实例解析 先从一个例子开始: public clas...
    99+
    2023-03-14
    Java Lambda表达式 Java Lambda原理
  • java LockSupport实现原理示例解析
    目录引言LockSupport常见函数LockSupport.parkLockSupport.unpark引言 前文中了解到AQS借助LockSupport.park和LockSup...
    99+
    2023-01-09
    java LockSupport原理 java LockSupport
  • HTML标签和属性应用实例分析
    本篇内容主要讲解“HTML标签和属性应用实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“HTML标签和属性应用实例分析”吧!HTML的主体结构HTML 页...
    99+
    2024-04-02
  • html标签语义化及其标题标签的示例分析
    这篇文章主要为大家展示了“html标签语义化及其标题标签的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“html标签语义化及其标题标签的示例分析”这篇文...
    99+
    2024-04-02
  • Linux nohup命令原理及实例解析
    nohup命令 在应用Unix/Linux时,我们一般想让某个程序在后台运行,于是我们将常会用 & 在程序结尾来让程序自动运行。比如我们要运行mysql在后台: /usr/local/mysql/bin/m...
    99+
    2022-06-03
    Linux nohup 命令
  • Java方法引用原理实例解析
    目录冗余的Lambda场景问题分析用方法引用改进代码方法引用符通过对象名引用成员方法通过类名称引用静态方法通过super引用成员方法通过this引用成员方法类的构造器引用数组的构造器...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作