Mybatis中ResultMap和动态SQL详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxd1435513775/article/details/80883842

1、ResultMap

1)、作用:自定义某个JavaBean的封装规则;
2)、属性参数:

a)、type:自定义规则的Java类型
b)、id:唯一id方便引用

3)、使用示例:

说明:
    id:定义主键,底层有优化;
    column:指定哪一列,指定判定的列名;
    property:指定对应的javaBean属性

<resultMap type="com.scorpios.mybatis.bean.Employee" id="MySimpleEmp">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>
</resultMap>

<!-- resultMap:自定义结果集映射规则;  -->
<!-- public Employee getEmpById(Integer id); -->
<select id="getEmpById"  resultMap="MySimpleEmp">
    select * from tbl_employee where id=#{id}
</select>

4)、使用场景分析

场景一:查询Employee的同时查询员工对应的部门。

<!--
    方式一:联合查询:级联属性封装结果集
  -->
<resultMap type="com.scorpios.mybatis.bean.Employee" id="MyDifEmp">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="gender" property="gender"/>
    <result column="did" property="dept.id"/>
    <result column="dept_name" property="dept.departmentName"/>
</resultMap>


<!-- 
    方式二:使用association定义关联的单个对象的封装规则,association可以指定联合的JavaBean对象;
        property="dept":指定哪个属性是联合的对象
        javaType:指定这个属性对象的类型[不能省略]
 -->
<resultMap type="com.scorpios.mybatis.bean.Employee" id="MyDifEmp2">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="gender" property="gender"/>

    <association property="dept" javaType="com.scorpios.mybatis.bean.Department">
        <id column="did" property="id"/>
        <result column="dept_name" property="departmentName"/>
    </association>
</resultMap>

<!--SQL语句-->
<!--  public Employee getEmpAndDept(Integer id);-->
<select id="getEmpAndDept" resultMap="MyDifEmp">
    SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id,
    d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d
    WHERE e.d_id=d.id AND e.id=#{id}
</select>


<!-- 方式三:使用association进行分步查询:
    1、先按照员工id查询员工信息;
    2、根据查询员工信息中的d_id值去部门表查出部门信息;
    3、部门设置到员工中;
 -->
 <resultMap type="com.scorpios.mybatis.bean.Employee" id="MyEmpByStep">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>

<!-- association定义关联对象的封装规则
    select:表明当前属性是调用select指定的方法查出的结果
    column:指定将哪一列的值传给这个方法
    流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性
 -->
    <association property="dept" select="com.scorpios.mybatis.dao.DepartmentMapper.getDeptById" column="d_id">
    </association>
 </resultMap>

 <!--  public Employee getEmpByIdStep(Integer id);-->
 <select id="getEmpByIdStep" resultMap="MyEmpByStep">
    select * from tbl_employee where id=#{id}
    <if test="_parameter!=null">
        and 1=1
    </if>
 </select>

场景二:查询部门的时候,将部门对应的所有员工信息也查询出来

<!-- public List<Employee> getEmpsByDeptId(Integer deptId); -->
<select id="getEmpsByDeptId" resultType="com.scorpios.mybatis.bean.Employee">
    select * from tbl_employee where d_id=#{deptId}
</select>

补充:鉴别器

1)、作用:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为;
2)、示例:

封装Employee:
    如果查出的是女生,就把部门信息查询出来,否则不查询;
    如果是男生,把last_name这一列的值赋值给email;

 <resultMap type="com.scorpios.mybatis.bean.Employee" id="MyEmpDis">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="email" property="email"/>
    <result column="gender" property="gender"/>

    <discriminator javaType="string" column="gender">
        <!--女生  resultType:指定封装的结果类型;不能缺少。/resultMap-->
        <case value="0" resultType="com.scorpios.mybatis.bean.Employee">
            <association property="dept" 
                select="com.scorpios.mybatis.dao.DepartmentMapper.getDeptById" column="d_id">
            </association>
        </case>
        <!--男生 ;如果是男生,把last_name这一列的值赋值给email; -->
        <case value="1" resultType="com.scorpios.mybatis.bean.Employee">
            <id column="id" property="id"/>
            <result column="last_name" property="lastName"/>
            <result column="last_name" property="email"/>
            <result column="gender" property="gender"/>
        </case>
    </discriminator>
 </resultMap>

补充:嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则,ofType:指定集合里面元素的类型;

<resultMap type="com.scorpios.mybatis.bean.Department" id="MyDept">
    <id column="did" property="id"/>
    <result column="dept_name" property="departmentName"/>

    <collection property="emps" ofType="com.scorpios.mybatis.bean.Employee">
        <!-- 定义这个集合中元素的封装规则 -->
        <id column="eid" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
    </collection>
</resultMap>

<!-- public Department getDeptByIdPlus(Integer id); -->
<select id="getDeptByIdPlus" resultMap="MyDept">
    SELECT d.id did,d.dept_name dept_name,e.id eid,e.last_name last_name,e.email email,e.gender gender
    FROM tbl_dept d
    LEFT JOIN tbl_employee e
    ON d.id=e.d_id
    WHERE d.id=#{id}
</select>

<!-- collection:分段查询 -->
<resultMap type="com.scorpios.mybatis.bean.Department" id="MyDeptStep">
    <id column="id" property="id"/>
    <id column="dept_name" property="departmentName"/>
    <collection property="emps" 
        select="com.scorpios.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
        column="{deptId=id}" fetchType="lazy"></collection>
</resultMap>

<!-- public Department getDeptByIdStep(Integer id); -->
<select id="getDeptByIdStep" resultMap="MyDeptStep">
    select id,dept_name from tbl_dept where id=#{id}
</select>

多列的值传递过去:
        将多列的值封装map传递;
        column="{key1=column1,key2=column2}"
        fetchType="lazy":表示使用延迟加载;
            - lazy:延迟
            - eager:立即

2、动态SQL

1)、where和if标签的使用

 <!-- 查询员工,要求,携带了哪个字段查询条件就带上这个字段的值 -->
 <!-- public List<Employee> getEmpsByConditionIf(Employee employee); -->
 <select id="getEmpsByConditionIf" resultType="com.scorpios.mybatis.bean.Employee">
    select * from tbl_employee
    <where>
        <if test="id!=null">
            id=#{id}
        </if>
        <if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
            and last_name like #{lastName}
        </if>
        <if test="email!=null and email.trim()!=&quot;&quot;">
            and email=#{email}
        </if> 
        <!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
        <if test="gender==0 or gender==1">
            and gender=#{gender}
        </if>
    </where>
 </select>

2)、trim标签的使用

作用:后面多出的and或者or,where标签不能解决
参数:
    prefix="":前缀:
            trim标签体中是整个字符串拼串后的结果。
            prefix给拼串后的整个字符串加一个前缀 
    prefixOverrides="":
            前缀覆盖: 去掉整个字符串前面多余的字符
    suffix="":后缀
            suffix给拼串后的整个字符串加一个后缀 
    suffixOverrides=""
            后缀覆盖:去掉整个字符串后面多余的字符 

 <!--public List<Employee> getEmpsByConditionTrim(Employee employee);  -->
 <select id="getEmpsByConditionTrim" resultType="com.scorpios.mybatis.bean.Employee">
    select * from tbl_employee

    <trim prefix="where" suffixOverrides="and">
        <if test="id!=null">
            id=#{id} and
        </if>
        <if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
            last_name like #{lastName} and
        </if>
        <if test="email!=null and email.trim()!=&quot;&quot;">
            email=#{email} and
        </if> 
        <!-- ognl会进行字符串与数字的转换判断  "0"==0 -->
        <if test="gender==0 or gender==1">
            gender=#{gender}
        </if>
     </trim>
 </select>

3)、choose标签的使用

扫描二维码关注公众号,回复: 3039804 查看本文章
 <!-- public List<Employee> getEmpsByConditionChoose(Employee employee); -->
 <select id="getEmpsByConditionChoose" resultType="com.scorpios.mybatis.bean.Employee">
    select * from tbl_employee 
    <where>
        <!-- 如果带了id就用id查,如果带了lastName就用lastName查;只会进入其中一个 -->
        <choose>
            <when test="id!=null">
                id=#{id}
            </when>
            <when test="lastName!=null">
                last_name like #{lastName}
            </when>
            <when test="email!=null">
                email = #{email}
            </when>
            <otherwise>
                gender = 0
            </otherwise>
        </choose>
    </where>
 </select>

4)、Set标签的使用

 <!--public void updateEmp(Employee employee);  -->
 <update id="updateEmp">
    update tbl_employee 
    <set>
        <if test="lastName!=null">
            last_name=#{lastName},
        </if>
        <if test="email!=null">
            email=#{email},
        </if>
        <if test="gender!=null">
            gender=#{gender}
        </if>
    </set>
    where id=#{id} 

5)、foreach标签的使用

    <!--
        collection:指定要遍历的集合,list类型的参数会特殊处理封装在map中,map的key就叫list
        item:将当前遍历出的元素赋值给指定的变量
        separator:每个元素之间的分隔符
        open:遍历出所有结果拼接一个开始的字符
        close:遍历出所有结果拼接一个结束的字符
        index:索引。遍历list的时候是index就是索引,item就是当前值
                      遍历map的时候index表示的就是map的key,item就是map的值
        #{变量名}:就能取出变量的值也就是当前遍历出的元素
      -->

 <!--public List<Employee> getEmpsByConditionForeach(List<Integer> ids);  -->
 <select id="getEmpsByConditionForeach" resultType="com.scorpios.mybatis.bean.Employee">
    select * from tbl_employee where id in 
    <foreach collection="ids" item="item_id" separator="," open="(" close=")">
        #{item_id}
    </foreach>
 </select>

 <!-- 使用foreach批量保存 -->
 <!--public void addEmps(@Param("emps")List<Employee> emps);  -->
 <!--MySQL下批量保存:可以foreach遍历;mysql支持values(),(),()语法-->
<!--方式一-->
<insert id="addEmps">
    insert into tbl_employee(
        <include refid="insertColumn"></include>
    ) 
    values
    <foreach collection="emps" item="emp" separator=",">
        (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
    </foreach>
 </insert>

 <!-- 方式二:这种方式需要数据库连接属性allowMultiQueries=true;
    这种分号分隔多个sql可以用于其他的批量操作(删除,修改) -->
 <!-- <insert id="addEmps">
    <foreach collection="emps" item="emp" separator=";">
        insert into tbl_employee(last_name,email,gender,d_id)
        values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
    </foreach>
 </insert> -->

6)、sql标签的使用

<!-- 
    抽取可重用的sql片段,方便后面引用 
        1、sql抽取:经常将要查询的列名,或者插入用的列名抽取出来方便引用
        2、include来引用已经抽取的sql:
        3、include还可以自定义一些property,sql标签内部就能使用自定义的属性
                include-property:取值的正确方式${prop},
                #{不能使用这种方式}
  -->

  <sql id="insertColumn">
        <if test="_databaseId=='oracle'">
            employee_id,last_name,email
        </if>
        <if test="_databaseId=='mysql'">
            last_name,email,gender,d_id
        </if>
  </sql>

3、两个内置参数

说明:在sql中获取参数时,不只是方法传递过来的参数可以被用来判断,取值。mybatis中默认还有两个内置参数:
1)、_parameter:代表整个参数

        单个参数:_parameter就是这个参数(对象就代表传过来的对象)
        多个参数:参数会被封装为一个map;_parameter就是代表这个map

2)、_databaseId:如果配置了databaseIdProvider标签,databaseId就是代表当前数据库的别名mysql。

猜你喜欢

转载自blog.csdn.net/zxd1435513775/article/details/80883842