zoukankan      html  css  js  c++  java
  • Mybatis sql映射文件浅析 Mybatis简介(三) 简介

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

     
    简介
    除了配置相关之外,另一个核心就是SQL映射,MyBatis 的真正强大也在于它的映射语句。
    Mybatis创建了一套规则以XML为载体映射SQL
    之前提到过,各项配置信息将Mybatis应用的整体框架搭建起来,而映射部分则是准备了一次SQL操作所需的信息
    一次SQL执行的主要事件是什么?
    输入参数解析,绝大多数SQL都是需要参数的
    SQL,通过SQL与数据库交互,所以最根本的是SQL,如果连SQL都没有,还扯个蛋蛋?
    结果映射,Mybatis可以帮我们完成字段与Java类型的映射
    image_5c524d1f_4a9
    所以说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_5c524d1f_63d
    而对于数据库的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_5c524d20_637b

    属性角度解析

    如果从属性的角度去看待各自的归属,每种属性都有各自的作用功能
    他们自身的功能也决定了那些类型才能拥有他
    比如键值的返回相关的useGeneratedKeys,就只可能发生在insert或者update中,只有他们才可能自动生成键
    image_5c524d20_c2
    以上为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_5c524d21_3917
     
    但是如果名称不对应又该怎么办?
    如果你的实体中的属性名称为userName,数据库字段名为name,Mybatis真的敢擅自的将这两者对应起来么?
    如下图所示,将之前的第一个示例稍作修改,增加一个StudentAnother,name更改为了userName,并将测试代码稍作修改
    从结果可以看得到,实体中的userName是null ,Mybatis肯定不敢擅自映射
    image_5c524d21_120a
    一种可行的方式是使用别名,通过数据库字段AS设置别名,就可以成功的完成映射
    image_5c524d21_2a0a
    通过别名,将数据库列名通过别名与属性字段建立映射关系,然后Mybatis就可以进行自动匹配了
    但是这种形式如果有多条SQL,每个SQL中都需要有别名,而且,如果后续有原因修改对象的字段名字,怎么办?
     
    另外的方式就是使用ResultMap,ResultMap的基础用法就是相当于设置别名
    但是借助于ResultMap,将别名的映射关系,维护在ResultMap中,所有使用到此映射类型的SQL都只需要关联这个ResultMap即可,如果有变更,仅仅需要变更ResultMap中的属性字段对应关系
    所有的SQL中的内容并不需要变动
     
    如下图所示,SQL中字段与实体类中不匹配,查询的结果为null
    右侧通过ResultMap将userName与列名name进行了映射,就可以成功读取数据
    image_5c524d21_3f71
     
    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_5c524d21_553b

    ResultMap-高级映射

    ResultMap当然不仅仅是像上面那样只是别名的转换,还可以进行更加复杂的映射
     
    对于结果集返回有哪些场景?
    “将一行记录映射为一个对象”与“将多行记录映射为对象列表”这两者本质是一样的,因为所需要做的映射是一样的
    比如上面数据库列名name到字段userName 的映射,不管是一行记录还是多行记录,他们都是一样的
    所以下面就以一个对象为例
     
    单纯的映射
    比如上面的例子,数据库列名与实体类中的字段一一对应(尽管名称不完全匹配,但是仍旧是一一对应的)
    组合的映射
    对于关系型数据库存在着关联关系的说法,一对一,一对多等
    这些关联关系最终也是要映射到对象中的, 所以对象中经常也会存在多种对应关系
    比如下面官方文档中的示例----查询博客详情 
    一个博客Blog 对应着一个作者Author ,一个作者可能有多个博文Post,每篇博文有零或多条的评论Post_Tag 和标签Tag
    image_5c524d21_751
    复制代码
    <!-- 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_5c524d21_7662
     
    可以看得出来对于组合映射又有一对一以及一对多两种形式
    (尽管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_5c524d21_1931
     
    上面就是通过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_5c524d21_2587
     
    借助于嵌套查询的形式 select属性,可以进行嵌套查询,通过嵌套查询的方式,相当于经过这个select,内部的字段映射部分被路由到另一个ResultMap(ResultType)中了
    而不需要在这个ResultMap中逐个重新的进行字段的映射指定
    但是select会有1+N的问题,但是使用select时这种使用外部ResultMap(resultType)的形式却是很有实用意义
    因为如果可以进行分离,被剥离的那一部分既可以单独使用,又可以嵌套在其他的ResultMap中,组合成更加强大的形式
    Mybatis是支持ResultMap嵌套的
    image_5c524d21_4ab0
    不仅仅association支持ResultMap的嵌套,collection也是支持的
    image_5c524d21_68a6
     
    可以看得出来,不管是借助于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_5c524d21_62a1
     
    在之前的例子中,一个blog有一个作者,但是如果一个博客还有一个联合作者怎么办?就像很多书可能不仅仅只有一个作者
    在这种场景下:有两个作者,他们的java类型必然都是Author
    而且他们的字段也是相同的,但是你不得不将他们进行区分,如下面SQL中所示,关联了两次Author表,通过前缀进行了区分
    一种解决方法就是将映射部分也重写两次,就像关联两次那样,仅仅是列名column前缀不同(可以将这两个ResultMap嵌入到blogResult中或者内容移入到外层ResultMap中,总之是写两遍映射)
    image_5c524d22_448c
     
    还有一种方法就是借助于columnPrefix,如下图所示,Blog中有两个Author的实例,一个是author另一个是coAuthor,关联关系,使用association
    他们都是Author类的实例,所以使用同样的ResultMap,通过columnPrefix对其中一个映射添加列前缀
    通过这个列前缀,就相当于有了另外的一个ResultMap,这个ResultMap就是指定的ResultMap中的column中每一个值都加上一个前缀
    image_5c524d22_ce9

    构造方法字段值注入

    使用Mybatis的核心就是为了执行SQL以及完成结果映射,结果的映射必然要创建最终需要映射的结果的对象
    通过ResultMap中的id和result指定的字段值都是通过setter设置器方法进行值的设置的
    既然最终就是要创建一个指定类型并且具有指定属性的对象结果,那么为什么一定非得是通过setter,难道不能在创建对象的时候通过构造方法初始化对象吗?
    Mybatis的ResultMap是支持构造方法设置的
    对于构造方法的属性值设置,通过constructor进行
    将之前的例子稍作修改,增加一个构造方法,复制一个ResultMap,添加constructor,就可以完成映射
    image_5c524d22_106a
     
    借助于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_5c524d22_3b4c

    鉴别器

    重新建一个表作为示例,配置信息还是如原来一样,SQL映射文件也是在第一个示例中的XML中编写的
    主要的信息如下,表以及数据以及实体类以及映射文件等
    image_5c524d22_78e7
     
    定义了三个类,一个Person类作为抽象模型(尽管我这个不是抽象类)
    一个成人类Adult和一个儿童类Child
    Adult增加了company属性,Child增加了school属性
    image_5c524d22_2a00
    每个类都有setter和getter方法,并且还重写了toString方法
     
    映射文件
    image_5c524d22_2ae3
     
    测试类
    复制代码
    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_5c524d22_35e4
     
     
    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_5c524d22_4d54
     
    https://www.cnblogs.com/noteless/p/10340536.html
  • 相关阅读:
    函数集
    2019.1.7
    第九次团队作业-测试报告与用户使用手册
    α版本升升备忘录下载链接
    系统设计和任务分配(个人)
    团队作业说明
    备忘录-团队选题报告
    需求分析与原型设计---升升备忘录
    项目——四则运算器
    Hello Django
  • 原文地址:https://www.cnblogs.com/sjqq/p/10476072.html
Copyright © 2011-2022 走看看