zoukankan      html  css  js  c++  java
  • Mybatis(二):Mybatis的映射文件sqlmapper详解

    MyBatis 真正的力量是在映射语句中。这里是奇迹发生的地方。对于所有的力量,SQL 映射的 XML 文件是相当的简单。当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 95%的代码量。MyBatis 的构建就是聚焦于 SQL 的,使其远离于普通的方式。

    SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):

    • cache – 配置给定命名空间的缓存。
    • cache-ref – 从其他命名空间引用缓存配置。
    • resultMap – 最复杂,也是最有力量的元素,用来描述如何从数据库结果集中来加载你的对象。
    • parameterMap – 已经被废弃了!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除。这里不会记录。
    • sql – 可以重用的 SQL 块,也可以被其他语句引用。
    • insert – 映射插入语句
    • update – 映射更新语句
    • delete – 映射删除语句
    • select – 映射查询语句

    1)cache

    参阅这篇文章里的二级缓存段落 MyBatis缓存详解

    2)sql

    用来定义可重用的sql语句块。

    <sql id="column">
        name,species,sex
    </sql>

    然后在sql映射中用<include/>标签引入:

    <select id="selectPetByName" parameterType="string" resultType="hashmap">
      select 
      <include refid="column"/> 
      from pet 
      where name = #{name}
    </select>

    这样就可以减少大量重复的sql书写工作。

    3)resultMap

    resultMap是mybatis中最强大最有用的配置,它可以帮助我们告别繁琐的while + resultSet.get(..) 而实现自动封装

    对于简单的sql查询,不需要配置resultMap,用hashmap来封装结果集会更好,这样会以字段名称为key,字段值为value来封装结果集:

    <select id="selectAllColumn" parameterType="string" resultType="hashmap">
      select <include refid="column"/> from pet where name = #{name}
    </select>

    但有时我们需要得到一个JavaBean对象,有两种方式可以实现,一种用reusltType来制定结果类型,另一种用resultMap来映射结果集和JavaBean对象

    第一种方式:

    <select id="selectOneByName" parameterType="string" resultType="com.mybatis.test.entity.Pet">
      select <include refid="column"/>
      from pet where name = #{name}
    </select>

    这样mybatis就会把查询出的结果封装到Pet对象中。

    第二种方式:

    配置resultMap

    <resultMap type="com.mybatis.test.entity.Pet" id="petMap">
      <result column="name" property="name" javaType="string" jdbcType="VARCHAR"/>
      <result column="species" property="species" javaType="string" jdbcType="VARCHAR" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/>
      <result column="sex" property="sex" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/>
    </resultMap>

    在sql映射中配置resultMap:

    <select id="cthSelect" resultMap="petMap">
      select <include refid="column"/>
      from pet
    </select>

    实际上应用第一种配置方式时,mybatis会在幕后根据字段名称自动创建一个resultMap。若表字段名称与JavaBean中的字段名称不匹配,还可以利用sql语句的as来修改sql结果集的字段名,使之与JavaBean中的字段名相匹配:

    <select id="selectOneByName" parameterType="string" resultType="com.mybatis.test.entity.Pet">
      select 
        name as name,
        species as species,
        sex as sex
      from pet where name = #{name}
    </select>

    但有的时候事情并没有这么简单,我们在很多情况下需要做一对多或多对一的联合查询,但把这些重组的字段再组合到一个新的bean对象中是不现实的,这样就需要对多个表和bean利用resultMap做联合配置,以满足实际的需求。

    下面以经典的“部门”对“员工”为例,做一对多和多对一的映射配置:

    Employee Bean:

    private Integer id;
    private String employeeName;
    private Integer age;
    private Department department = new Department();

    Department Bean:

    private Integer id;
    private String departmentName;
    private List<Employee> employees;

    一个部门对应多个员工,而一个员工属于一个部门,我们分别从部门和员工的角度出发,来做一对多和多对一的映射。

    员工-部门的多对一映射:

    <resultMap type="com.mybatis.test.entity.Employee" id="employeeMap">
    <!-- 
    id : 一个 ID 结果;标记结果作为 ID 可以帮助提高整体效能.
    result : 注入到字段或 JavaBean 属性的普通结果
    association : 一个复杂的类型关联;许多结果将包成这种类型.
    collection : 复杂类型的集
    
    -->
      <id property="id" column="id"/>
      <result property="employeeName" column="name"/>
      <result property="age" column="age"/>
      <association property="department" javaType="Department">
        <id property="id" column="id"/>
        <result property="departmentName" column="department_name"/>
      </association>
    </resultMap>

    用<association/>来指定每一个员工多对应的部门。

    部门-员工的一对多映射:

    <resultMap type="Department" id="departmentMap">
      <id property="id" column="id"/>
      <result property="departmentName" column="department_name"/>
      <collection property="employees" ofType="Employee" column="dept_id">
        <id property="id" column="id"/>
        <result property="employeeName" column="name"/>
        <result property="age" column="age"/>
      </collection>
    </resultMap>

    利用<collection/>来制定多是一方。在配置多对一关系时,需要在<collection/>中制定关联字段,column="dept_id",这样mybatis就会根据这个字段来找出所有属于该部门的员工,并将其封装到集合中。

    在定义resultMap时,还可以利用javaType、jdbcType和typeHandler来实现java数据类型和数据库字段类型的对应关系及其特定的操作动作,eg:
    在mybatis核心配置文件中生命自定义类型处理器:

    <typeHandlers>
      <typeHandler javaType="string" jdbcType="VARCHAR" handler="com.mybatis.test.handler.MyStringTypeHandler"/>
    </typeHandlers>

    自定义类型处理器:

    package com.mybatis.test.handler;
    
    import java.sql.CallableStatement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import org.apache.ibatis.type.JdbcType;
    import org.apache.ibatis.type.TypeHandler;
    
    public class MyStringTypeHandler implements TypeHandler<String>{
    
        @Override
        public void setParameter(PreparedStatement ps, int i, String parameter,
                JdbcType jdbcType) throws SQLException {
               if("".equals(parameter) || "null".equals(parameter) 
                       || parameter == null || "NULL".equals(parameter)){
                   parameter = "blank";
               }
               ps.setString(i, parameter);
        }
    
        @Override
        public String getResult(ResultSet rs, String columnName)
                throws SQLException {
            String result = rs.getString(columnName);
            if("null".equals(result) || "".equals(result) 
                     || result == null  || "NULL".equals(result)){
    
                result = "blank";
            }
            return result;
        }
    
        @Override
        public String getResult(ResultSet rs, int columnIndex) throws SQLException {
            String result = rs.getString(columnIndex);
            if("null".equals(result) || "".equals(result)
                    || result == null || "NULL".equals(result)){
                result = "blank";
            }
            return result;
        }
    
        @Override
        public String getResult(CallableStatement cs, int columnIndex)
                throws SQLException {
            String result = cs.getString(columnIndex);
            if("null".equals(result) || "".equals(result) 
                    || result == null || "NULL".equals(result)){
                result = "blank";
            }
            return null;
        }
    
    }

    该类型处理器既可以用于设置参数时、也可以用于获取结果时对空值的处理。

    在resultMap中进行配置:

    <resultMap type="com.mybatis.test.entity.Pet" id="petMap">
               <result column="name" property="name" javaType="string" jdbcType="VARCHAR"/>
               <result column="species" property="species" javaType="string" jdbcType="VARCHAR" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/>
               <result column="sex" property="sex" typeHandler="com.mybatis.test.handler.MyStringTypeHandler"/>
        </resultMap>

    这样,如果从数据库表中查询出的结果为null时,就会用自定义类型处理器中的方式进行处理。

    在设置参数的时候可以像下面这样应用自定义类型处理器对参数进行处理:

    <insert id="insertNullByMyTypeHandler" parameterType="Pet">
                insert into pet 
                      (<include refid="column"/>) 
                values 
                      (
                         #{name,jdbcType=UNDEFINED,javaType=string,handler=com.mybatis.test.handler.MyTypeHandler},
                         #{species},
                         #{sex}
                      )
         </insert>

    3)insert、update、delete

    这三个标签分别配置对应的sql语句,由于这三中sql都是DML,所以在用法上基本相同:

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

    id:该sql语句在当前名称空间下的唯一标识符,用户调用该sql语句。

    parameterType:sql语句的参数类型,可以是mybatis提供的别名(int、string、hashmap、list等),也可以是自定义类似。需要注意的是,若参数类型为hashmap或自定义bean等,在利用#{fieldName}取得参数的值时用到的名称需要与map中的key或bean中的字段名称保证一致,否则会取不到数据,如果是string或int等,则名称没有现实,只起到标识的作用。

    flushCache:刷新缓存,若将该属性设置为true,则调用该sql时,会到时缓存被清空。默认为false。

    statementType:设置预编译sql语句的方式,mybatis提供了三种:

    STATEMENT,PREPARED,CALLABLE

    默认是PREPARED类型。

    timeout:设置获取数据库操作结果的最大等事件。默认不对其进行设置,有数据库取得来决定。

    4)select

    select语句是最常用的数据库操作,相对于DML操作,mybatis对select语句映射的支持明显更强。查询语句的特殊之处在于既有输入也有输出,下面对select语句映射做简要概述。

    一个最简单的查询映射:

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

    该语句按照id查询一条person记录,其中输入参数是int类型,虽然#{id}中的id与数据表中的id列名保存一致,但前面已经说过,对于基本数据类型的参数,名称没有现实,任何名字mybatis都可以取到参数的值。返回结果是hashmap,也就是Java中对应的HashMap,定义该结果类型后,mybatis会将查询结果封装到一个map对象中,key值为字段名称,value为该字段的值。

    Mybatis对select标签提供了丰富的属性,以支持对select语句的更细粒度配置:

    <select
      id="selectPerson"
      parameterType="int"
      parameterMap="deprecated"
      resultType="hashmap"
      resultMap="personResultMap"
      flushCache="false"
      useCache="true"
      timeout="10000"
      fetchSize="256"
      statementType="PREPARED"
      resultSetType="FORWARD_ONLY">

    其中的本分属性前面已经介绍过,这里就不在冗述了。
    useCache:配置二级缓存,当mybatis开启二级缓存时,查询有默认是应用二级缓存的,若不想将某一个DQL与二级缓存联系起来,可将该属性设置为false。
    fetchSize:设置每次查询的最大返回结果,通常不设置改属性。

  • 相关阅读:
    [saiku] 系统登录成功后查询Cubes
    216. Combination Sum III
    215. Kth Largest Element in an Array
    214. Shortest Palindrome
    213. House Robber II
    212. Word Search II
    211. Add and Search Word
    210. Course Schedule II
    分硬币问题
    开始学习Python
  • 原文地址:https://www.cnblogs.com/shamo89/p/8051746.html
Copyright © 2011-2022 走看看