• 如何优雅的使用MyBatis?


    ​本文目录

    什么是 MyBatis ?

    映射器(mappers)

    typeAliases 类型别名减少类完全限制名的冗余

    处理枚举类型

    多行插入

    重用 SQL 代码段,消除重复

    字符串替换#{}和${}的区别

    Result Maps,表的列名和类的属性名不对应怎么处理?

    MyBatis关联的嵌套查询

    MyBatis集合的嵌套查询

    动态 SQL,如何优雅的构建动态Sql

    Where 构建动态查询条件

    choose, when, otherwise 从条件中选其一项

    set 动态包含需要更新的列

    foreach 构建 IN 条件语句

    bind 构建like 查询


    什么是 MyBatis ?

    MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

    映射器(mappers)

    你需要告诉 MyBatis 到哪里去找映射文件。你可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等。

    <!-- 使用相对于类路径的资源引用 -->
    <mappers>
      <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
      <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
      <mapper resource="org/mybatis/builder/PostMapper.xml"/>
    </mappers>
    
    <!-- 使用映射器接口实现类的完全限定类名  -->
    <mappers>
      <mapper class="org.mybatis.builder.AuthorMapper"/>
      <mapper class="org.mybatis.builder.BlogMapper"/>
      <mapper class="org.mybatis.builder.PostMapper"/>
    </mappers>
    
    <!-- 将包内的映射器接口实现全部注册为映射器 -->
    <mappers>
      <package name="org.mybatis.builder"/>
    </mappers>

    typeAliases 类型别名减少类完全限制名的冗余

    类型别名是为 Java 类型设置一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。例如:

    <typeAliases>
      <typeAlias alias="Author" type="domain.blog.Author"/>
      <typeAlias alias="Blog" type="domain.blog.Blog"/>
      <typeAlias alias="Comment" type="domain.blog.Comment"/>
      <typeAlias alias="Post" type="domain.blog.Post"/>
      <typeAlias alias="Section" type="domain.blog.Section"/>
      <typeAlias alias="Tag" type="domain.blog.Tag"/>
    </typeAliases>

    当这样配置时,Blog可以用在任何使用domain.blog.Blog的地方。

    也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

    <typeAliases>
      <package name="domain.blog"/>
    </typeAliases>

    处理枚举类型

    若想映射枚举类型 Enum,则需要从 EnumTypeHandler 或者 EnumOrdinalTypeHandler 中选一个来使用。

    比如说我们想存储取近似值时用到的舍入模式。默认情况下,MyBatis 会利用 EnumTypeHandler 来把 Enum 值转换成对应的名字。

    注意 EnumTypeHandler 在某种意义上来说是比较特别的,其他的处理器只针对某个特定的类,而它不同,它会处理任意继承了 Enum 的类。

    不过,我们可能不想存储名字,相反我们的 DBA 会坚持使用整形值代码。那也一样轻而易举: 在配置文件中把 EnumOrdinalTypeHandler 加到 typeHandlers 中即可, 这样每个 RoundingMode 将通过他们的序数值来映射成对应的整形

    <!-- mybatis-config.xml -->
    <typeHandlers>
      <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>
    </typeHandlers>

    多行插入

     可以传入一个Authors数组或集合,并返回自动生成的主键。

    <insert id="insertAuthor" useGeneratedKeys="true"
        keyProperty="id">
      insert into Author (username, password, email, bio) values
      <foreach item="item" collection="list" separator=",">
        (#{item.username}, #{item.password}, #{item.email}, #{item.bio})
      </foreach>
    </insert>

    重用 SQL 代码段,消除重复

    sql这个元素可以被用来定义可重用的 SQL 代码段,可以包含在其他语句中。它可以被静态地(在加载参数) 参数化. 不同的属性值通过包含的实例变化. 比如:

    <sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
    

    这个 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>
    

    字符串替换#{}和${}的区别

    默认情况下,使用 #{} 格式的语法会导致 MyBatis 创建 PreparedStatement 参数并安全地设置参数(就像使用 ? 一样,会有'')。这样做更安全,更迅速,通常也是首选做法。#{id},它告诉 MyBatis 创建一个预处理语句参数,通过 JDBC,这样的一个参数在 SQL 中会由一个“?”来标识,并被传递到一个新的预处理语句中,就像这样:

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

    不过有时你就是想直接在 SQL 语句中插入一个不转义的字符串。比如,像 ORDER BY,你可以这样来使用:

    ORDER BY ${columnName}
    

    这里用${} MyBatis 不会修改或转义字符串。

    NOTE: 用这种方式接受用户的输入,并将其用于语句中的参数是不安全的,会导致潜在的 SQL 注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验。

    Result Maps,表的列名和类的属性名不对应怎么处理?

    MyBatis 会在幕后自动创建一个 ResultMap,再基于属性名来映射列到 JavaBean 的属性上。如果列名和属性名没有精确匹配,可以在 SELECT 语句中对列使用别名(这是一个 基本的 SQL 特性)来匹配标签。比如:

    方法一:

    <select id="selectUsers" resultType="User">
      select
        user_id             as "id",
        user_name           as "userName",
        hashed_password     as "hashedPassword"
      from some_table
      where id = #{id}
    </select>

    ResultMap 最优秀的地方在于,虽然你已经对它相当了解了,但是根本就不需要显式地用到他们。 上面这些简单的示例根本不需要下面这些繁琐的配置。 出于示范的原因,让我们来看看最后一个示例中,如果使用外部的 resultMap 会怎样,这也是解决列名不匹配的另外一种方式。方法二:

    <resultMap id="userResultMap" type="User">
      <id property="id" column="user_id" />
      <result property="username" column="user_name"/>
      <result property="password" column="hashed_password"/>
    </resultMap>
    
    <select id="selectUsers" resultMap="userResultMap">
      select user_id, user_name, hashed_password
      from some_table
      where id = #{id}
    </select>

    MyBatis关联的嵌套查询

    <resultMap id="blogResult" type="Blog">
      <id property="id" column="blog_id" />
      <result property="title" column="blog_title"/>
      <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
    </resultMap>
    
    <resultMap id="authorResult" type="Author">
      <id property="id" column="author_id"/>
      <result property="username" column="author_username"/>
      <result property="password" column="author_password"/>
      <result property="email" column="author_email"/>
      <result property="bio" column="author_bio"/>
    </resultMap>
    
    <select id="selectBlog" resultMap="blogResult">
      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
      from Blog B left outer join Author A on B.author_id = A.id
      where B.id = #{id}
    </select>

    在上面的示例中你可以看到博客的作者关联代表着“authorResult”结果映射来加载作 者实例。

    非常重要: id元素在嵌套结果映射中扮演着非 常重要的角色。你应该总是指定一个或多个可以唯一标识结果的属性。实际上如果你不指定它的话, MyBatis仍然可以工作,但是会有严重的性能问题。在可以唯一标识结果的情况下, 尽可能少的选择属性。主键是一个显而易见的选择(即使是复合主键)。

    MyBatis集合的嵌套查询

    继续上面的示例,一个博客只有一个作者。但是博客有很多文章。在博客类中, 这可以由下面这样的写法来表示:

    private List<Post> posts;
    

    它和关联完全相同,除了它应用了一个“ofType”属性

    <resultMap id="blogResult" type="Blog">
      <id property="id" column="blog_id" />
      <result property="title" column="blog_title"/>
      <collection property="posts" ofType="Post">
        <id property="id" column="post_id"/>
        <result property="subject" column="post_subject"/>
        <result property="body" column="post_body"/>
      </collection>
    </resultMap>
    
    <select id="selectBlog" resultMap="blogResult">
      select
      B.id as blog_id,
      B.title as blog_title,
      B.author_id as blog_author_id,
      P.id as post_id,
      P.subject as post_subject,
      P.body as post_body,
      from Blog B
      left outer join Post P on B.id = P.blog_id
      where B.id = #{id}
    </select>

    动态 SQL,如何优雅的构建动态Sql

    MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

    Where 构建动态查询条件

    where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。

    <select id="findActiveBlogLike"
         resultType="Blog">
      SELECT * FROM BLOG 
      <where> 
        <if test="state != null">
             state = #{state}
        </if> 
        <if test="title != null">
            AND title like #{title}
        </if>
        <if test="author != null and author.name != null">
            AND author_name like #{author.name}
        </if>
      </where>
    </select>

    如果 where 元素没有按正常套路出牌,我们可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为下面代码:(prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。)

    <trim prefix="WHERE" prefixOverrides="AND |OR ">
      ... 
    </trim>
    

    choose, when, otherwise 从条件中选其一项

    有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。例如:提供了“title”就按“title”查找,提供了“author”就按“author”查找的情形,若两者都没有提供,就返回所有符合条件的 BLOG(实际情况可能是由管理员按一定策略选出 BLOG 列表,而不是返回大量无意义的随机结果)。

    <select id="findActiveBlogLike"
         resultType="Blog">
      SELECT * FROM BLOG WHERE state = ‘ACTIVE’
      <choose>
        <when test="title != null">
          AND title like #{title}
        </when>
        <when test="author != null and author.name != null">
          AND author_name like #{author.name}
        </when>
        <otherwise>
          AND featured = 1
        </otherwise>
      </choose>
    </select>

    set 动态包含需要更新的列

    set 元素可以用于动态包含需要更新的列,而舍去其它的。比如:

    <update id="updateAuthorIfNecessary">
      update Author
        <set>
          <if test="username != null">username=#{username},</if>
          <if test="password != null">password=#{password},</if>
          <if test="email != null">email=#{email},</if>
          <if test="bio != null">bio=#{bio}</if>
        </set>
      where id=#{id}
    </update>

    foreach 构建 IN 条件语句

    动态 SQL 的另外一个常用的操作需求是对一个集合进行遍历,通常是在构建 IN 条件语句的时候。比如:

    <select id="selectPostIn" resultType="domain.blog.Post">
      SELECT *
      FROM POST P
      WHERE ID in
      <foreach item="item" index="index" collection="list"
          open="(" separator="," close=")">
            #{item}
      </foreach>
    </select>

    bind 构建like 查询

    bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:

    <select id="selectBlogsLike" resultType="Blog">
      <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
      SELECT * FROM BLOG
      WHERE title LIKE #{pattern}
    </select>
  • 相关阅读:
    Contains,Exists,Any,Count 比较是否存在某个元素
    RabbitMQ (十六) 消息队列的应用场景 (转)
    Quartz.NET 3.0.7 + MySql 动态调度作业+动态切换版本+多作业引用同一程序集不同版本+持久化+集群(四)
    RabbitMQ (十五) 镜像集群 + HAProxy1.7.8 负载均衡
    RabbitMQ (十四) 普通集群
    RabbitMQ (十三) 集群+单机搭建(window)
    (转) HA的几种方案
    RabbitMQ (十二) 消息确认机制
    RabbitMQ (十一) 消息确认机制
    VIM操作
  • 原文地址:https://www.cnblogs.com/xiaoyao2011/p/16390467.html
Copyright © 2020-2023  润新知