• myBatis04 Mapper文件


    1、标签和属性

    1.1、Mapper内部的顶级标签

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

    1.2、数据变更

    insert,update,delete三个标签用法基本差不错,比较简单。

    <insert
      id="insertAuthor"
      parameterType="domain.blog.Author"
      flushCache="true"
      statementType="PREPARED"
      keyProperty=""
      keyColumn=""
      useGeneratedKeys=""
      timeout="20">
    
    <update
      id="updateAuthor"
      parameterType="domain.blog.Author"
      flushCache="true"
      statementType="PREPARED"
      timeout="20">
    
    <delete
      id="deleteAuthor"
      parameterType="domain.blog.Author"
      flushCache="true"
      statementType="PREPARED"
      timeout="20">
    

    相关属性:

    属性描述
    id 在命名空间中唯一的标识符,可以被用来引用这条语句。
    parameterType 将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
    flushCache 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:(对 insert、update 和 delete 语句)true。
    timeout 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
    statementType 可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
    useGeneratedKeys (仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
    keyProperty (仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
    keyColumn (仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。
    databaseId 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。

    批量新增的用法

    如果你的数据库还支持多行插入, 你也可以传入一个 Author 数组或集合,并返回自动生成的主键。

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

    1.3、数据查询

    select标签,用于完成数据的查询,普通的查询比较简单。

    复杂的用法:动态Sql,与resultMap结合

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

    相关属性:

    属性描述
    keyProperty selectKey 语句结果应该被设置到的目标属性。如果生成列不止一个,可以用逗号分隔多个属性名称。
    keyColumn 返回结果集中生成列属性的列名。如果生成列不止一个,可以用逗号分隔多个属性名称。
    resultType 结果的类型。通常 MyBatis 可以推断出来,但是为了更加准确,写上也不会有什么问题。MyBatis 允许将任何简单类型用作主键的类型,包括字符串。如果生成列不止一个,则可以使用包含期望属性的 Object 或 Map。
    resultMap 用来引用外部结果集配置,完成查询字段与Java对象属性的映射,与resultType不能同时使用。
    order 可以设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它首先会生成主键,设置 keyProperty 再执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey中的语句 - 这和 Oracle 数据库的行为相似,在插入语句内部可能有嵌入索引调用。
    statementType 和前面一样,MyBatis 支持 STATEMENTPREPARED 和 CALLABLE 类型的映射语句,分别代表 StatementPreparedStatement 和 CallableStatement 类型。

    1.4 sql代码片段

    这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。 参数可以静态地(在加载的时候)确定下来,并且可以在不同的 include 元素中定义不同的参数值。比如:

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

    1.5 cache缓存

    MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。

    默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:

    。。。

    1.6 cache-ref

    。。。

    2、输入参数

    Mapper操作内会包含参数,参数定义方式:

    1)#{参数名},主要用于字段值位置。

    2)${参数名},主要用于字符串替换,当替换参数值时有注入的风险。

    参数值传入支持简单类型也支持复杂类型,如果只有一个参数,可以不需要通过parameterType指定参数类型。

    参数名后边可以指定其它的数据类型声明,例如:

    常用的类型:javaType,jdbcType,typeHandler,numericScale,mode,resultMap

    jdbcType的取值必须是org.apache.ibatis.type.JdbcType枚举类型中的某一个类型。

    typeHandler是数据值处理器,用来完成数据的二次处理。

    numericScale如果是数值类型,可以通过该属性指定保留小数的位数。

    mode 属性允许你指定 INOUT 或 INOUT 参数,如果是存储过程的参数才需要。

    resultMap 用来将结果集 ResultMap 映射到参数的类型上。

    #{isDelete,javaType=java.lang.String,jdbcType=BIT,typeHandler=db.TypeHandles.isDeleteTypeHandle}
    #{height,javaType=double,jdbcType=NUMERIC,numericScale=2}
    
    #{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

    简单类型方法:

    <select id="selectUsers" resultType="User">
      select id, username, password
      from users
      where id = #{id}
    </select>
    

    负责类型用法:如果 User 类型的参数对象传递到了语句中,会查找 id、username 和 password 属性,然后将它们的值传入预处理语句的参数中。

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

    参数替换的应用举例:

    按照任意的列进行查询

    @Select("select * from user where ${column} = #{value}")
    User findByColumn(@Param("column") String column, @Param("value") String value);
    

    按照任意列进行排序

    ORDER BY ${columnName} 

    3、输出映射

    resultType,用来指定输出的具体类型,查询列名需要和类型的字段名保持统一,字段名和属性不对应是要使用别名方式。

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

    myBatis会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上

    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>

    4、动态Sql

     动态 SQL 是 MyBatis 的强大特性之一。

    4.1、if

    判断表达式是否成立,成立则包含代码块内的语句

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

     这里的test属性值应该是合法的Java代码,参数内部包含的属性可以直接使用。

    4.2、choose、when、otherwise

    多重判断,类似于switch语句。

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

    4.3、where

    当通过if拼接where查询条件的时候,需要在前边增加一个1=1的语句前缀,如果通过where标签,则可以省略掉。

    <select id="findActiveBlogLike"
         resultType="Blog">
      SELECT * FROM BLOG
      <where>
        <if test="state != null">
            AND 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 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

    4.4、set

    用于动态更新语句的类似解决方案叫做 setset 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:

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

    4.5、foreach

    动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)

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

    foreach元素的属性主要有item,index,collection,open,separator,close。

    • item:集合中元素迭代时的别名,该参数为必选。
    • index:在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选
    • open:foreach代码的开始符号,一般是(和close=")"合用。常用在in(),values()时。该参数可选
    • separator:元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。
    • close: foreach代码的关闭符号,一般是)和open="("合用。常用在in(),values()时。该参数可选。
    • collection: 要做foreach的对象,作为入参时,List对象默认用"list"代替作为键,数组对象有"array"代替作为键,Map对象没有默认的键。当然在作为入参时可以使用@Param("keyName")来设置键,设置keyName后,list,array将会失效。 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子:如果User有属性List ids。入参是User对象,那么这个collection = "ids".如果User有属性Ids ids;其中Ids是个对象,Ids有个属性List id;入参是User对象,那么collection = "ids.id"

    在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况: 

    • 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list .
    • 如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array .
    • 如果传入的参数时多个的时候,可以封装在一个类内部,通过类内部属性来包含集合对象。
    • 如果传入的参数是多个的时候,也可以将参数封装成一个Map了,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key.

    使用例子1 - 单参数List:

    <select id="countByUserList" resultType="_int" parameterType="list">
    select count(*) from users
      <where>
        id in
        <foreach item="item" collection="list" separator="," open="(" close=")" index="">
          #{item.id, jdbcType=NUMERIC}
        </foreach>
      </where>
    </select>c

    测试代码:

    @Test
      public void shouldHandleComplexNullItem() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        try {
          Mapper mapper = sqlSession.getMapper(Mapper.class);
          User user1 = new User();
          user1.setId(2);
          user1.setName("User2");
          List<User> users = new ArrayList<User>();
          users.add(user1);
          users.add(null);
          int count = mapper.countByUserList(users);
          Assert.assertEquals(1, count);
        } finally {
          sqlSession.close();
        }
      }
    

    使用例子2 - 单参数Array数组:

    <select id="dynamicForeach2Test" resultType="Blog">
         select * from t_blog where id in
         <foreach collection="array" index="index" item="item" open="(" separator="," close=")">
              #{item}
         </foreach>
    </select>c

    测试代码:

    @Test
     public void dynamicForeach2Test() {
             SqlSession session = Util.getSqlSessionFactory().openSession();
             BlogMapper blogMapper = session.getMapper(BlogMapper.class);
             int[] ids = new int[] {1,3,6,9};
             List blogs = blogMapper.dynamicForeach2Test(ids);
             for (Blog blog : blogs)
             System.out.println(blog);
             session.close();
     }

    使用例子3 - 自己把参数封装成Map的类型:

    <select id="dynamicForeach3Test" resultType="Blog">
             select * from t_blog where title like "%"#{title}"%" and id in
              <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
                   #{item}
              </foreach>
     </select>

    测试代码:

    @Test
        public void dynamicForeach3Test() {
            SqlSession session = Util.getSqlSessionFactory().openSession();
             BlogMapper blogMapper = session.getMapper(BlogMapper.class);
              final List ids = new ArrayList();
              ids.add(1);
              ids.add(2);
              ids.add(3);
              ids.add(6);
             ids.add(7);
             ids.add(9);
            Map params = new HashMap();
             params.put("ids", ids);
             params.put("title", "中国");
            List blogs = blogMapper.dynamicForeach3Test(params);
             for (Blog blog : blogs)
                 System.out.println(blog);
             session.close();
         }
    

    4.6、bind

    完成模糊查询。

    bind元素,可以通过OGNL表达式创建一个上下文变量,在模块查询中可以使用。

        <select id="getEmpsTestInnerParameter" resultType="com.hand.mybatis.bean.Employee">
            <!-- bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值 -->
            SELECT * FROM emp
            <where>
                <!--eName是emp表中一个属性值-->
                <bind name="bindName" value="'%'+eName+'%'"/>
                <if test="_parameter!=null">
                    ename like #{bindName}
                </if>
            </where>
        </select>

    4.7、多数据库支持

    如果配置了 databaseIdProvider,你就可以在动态代码中使用名为 “_databaseId” 的变量来为不同的数据库构建特定的语句。比如下面的例子:

    <insert id="insert">
      <selectKey keyProperty="id" resultType="int" order="BEFORE">
        <if test="_databaseId == 'oracle'">
          select seq_users.nextval from dual
        </if>
        <if test="_databaseId == 'db2'">
          select nextval for seq_users from sysibm.sysdummy1"
        </if>
      </selectKey>
      insert into users values (#{id}, #{name})
    </insert>
    
  • 相关阅读:
    剑指Offer(Java版)第三十七题:输入一个正整数数组,把数组里所有数字拼接起来排成一个数, 打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321}, 则打印出这三个数字能排成的最小数字为321323。
    剑指Offer(Java版)第三十六题:从1到非负整数n中1出现的次数 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数? 为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次, 但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化, 可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
    剑指Offer(Java版)第三十五题:给一个数组,返回它的最大连续子序列的和
    剑指Offer(Java版)第三十四题:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
    剑指Offer(Java版)第三十三题:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。 由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
    剑指Offer(Java版)第三十二题:输入一个字符串,按字典序打印出该字符串中字符的所有排列。 例如输入字符串abc, 则打印出由字符a,b,c所能排列出来的 所有字符串abc,acb,bac,bca,cab和cba。
    剑指Offer(Java版)第三十一题:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。 要求不能创建任何新的结点,只能调整树中结点指针的指向。
    剑指Offer(Java版)第三十题(有难度):输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点, 另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。
    剑指Offer(Java版)第二十九题:输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。 路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
    剑指Offer(Java版)第二十八题:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。 如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
  • 原文地址:https://www.cnblogs.com/feihusurfer/p/15877341.html
Copyright © 2020-2023  润新知