明哥复习Mybatis(2)

不是原创,整理尚硅谷的内容得到的

六、自定义映射ResultMap

①处理字段和属性名不一致的情况

处理字段名和属性名不一致的方式一:为表中字段增加别名:

select emp_id empId,emp_name empName,age,gender  from t_emp where emp_id=#{empId}

注意,表中没有empId和empName两个字段,MyBatis是根据查询结果的字段名为属性名赋值,这边字段名和属性名不一致,肯定是对应不上的。

方式二:设置一个全局配置

 在全局配置中设置标签:

<setting name="mapUnderscoreToCamelCase" value="true"/>

这个标签必须要求符合MySQL和java命名规范才可以继续,Mybatis中的核心配置文件中设置一个全局配置,自动将下划线转化为驼峰

方式三:使用resultMap进行操作

<resultMap id="EmpAndDept" type="Emp">   
    <id column="emp_id" property="empId"></id>
    <result column="emp_name" property="empName"></result>
    <result column="age" property="age"></result>
    <result column="gender" property="gender"></result>
</resultMap>

最上面id表示这个标签的唯一标识(这个id要和sql语句进行关联),type表示要处理的实体类

result处理普通字段和实体类对应关系

 id用于处理主键

②处理多对一的映射关系(主要有三种方式):

方式一:多表联查,也就是用级联的方式,这时也是设置一个ResultMap就可以了,具体看下面这段代码:

<resultMap id="EmpAndDept" type="Emp">
    <id column="emp_id" property="empId"></id>
    <result column="emp_name" property="empName"></result>
    <result column="age" property="age"></result>
    <result column="gender" property="gender"></result>
    <result column="dept_id" property="dept.deptId"></result>
    <result column="dept_name" property="dept.deptName"></result>
</resultMap>
<select id="getEmpAndDeptByEmpIdOne" resultMap="EmpAndDept">
    select t_emp.*,t_dept.*
    from t_emp
    left join t_dept
    on t_emp.dept_id = t_dept.dept_id
    where t_emp.emp_id=#{empId}
</select>

现在要通过员工id获取员工部门id和员工的全部信息,这时典型的多对一(多个员工对应一个部门),那么要在员工信息里面多一个属性(这个属性就是部门),这个时候MyBatis进行查询的时候,对于查询的结果dept_id和dept_name,由于我们在员工类中没有这两个属性,因此没有办法进行赋值,于是要用resultMap进行对应。

方式二:使用association处理映射关系

<resultMap id="empAndDeptResultMap" type="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>

        <association property="dept" javaType="Dept">
            <id column="dept_id" property="deptId"></id>
            <id column="dept_name" property="deptName"></id>
        </association>
</resultMap>

标签property是用来表示要处理的属性,而javaType是设置要处理的属性的类型,这里本该写全类名,但是由于我在核心配置文件中为类型起了别名,所以可以这样写。

方式三:分布查询,写成两个sql语句

查询一:

 <resultMap id="empAndDeptByStepResultResultMap" type="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age" property="age"></result>
        <result column="gender" property="gender"></result>
        <association property="dept" fetchType="lazy"                     select="com.atguigu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
        column="dept_id">
        </association>
    </resultMap>
    <select id="getEmpAndDeptByStepOne" resultMap="empAndDeptByStepResultResultMap">
        select *from t_emp where emp_id=#{empId}
    </select>

查询二:

<select id="getEmpAndDeptByStepTwo" resultType="Dept">
    select *from t_dept where dept_id=#{deptId}
</select>

说白了就是查两次,第一次查询部门id,第二次用查到的部门id去查询部门的信息;

这时association标签中字段有下面的含义:

Properties表示设置需要处理映射关系的属性的属性名

select表示我要跳转到哪个sql语句,注意这边(namespace+sql的id构成sql的唯一标识,也就是Mapper接口的抽象方法的全类名)

column表示将sql查询结果的某个字段作为分步查询的条件

这种方法单独有优势:

可以实现懒加载,也就是如果我单独只要获取员工姓名,那么也就不需要进行加载dept的信息了,此时只需要(核心)配置下面两个标签就可以了,也可以通过上面所描述的fetchType="lazy"标签来进行处理。

<!--延迟加载全局开关-->
        <setting name="lazyLoadingEnabled" value="true"/>
<!--   aggressiveLazyLoading 当开启时,任何sql查询的加载会导致所有属性的加载     -->
        <setting name="aggressiveLazyLoading" value="false"/>

③处理一对多的映射关系

下面要查询一个部门里面的所有员工信息,那么要为部门类添加一个list这个属性,为这个属性加上泛型:员工。这时候只有两种处理方式:多步查询和collection。

方式一:使用Collection进行处理

<resultMap id="DeptAndEmpResultMap" type="Dept">

        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps" ofType="Emp">
            <id column="emp_id" property="empId"></id>
            <result column="emp_name" property="empName"></result>
            <result column="age" property="age"></result>
            <result column="gender" property="gender"></result>
        </collection>
    </resultMap>

<!-- 要处理的是Dept,因为Dept中有一个属性找不到映射关系,这边是处理映射关系的,所以Type是dept-->

ofType用于处理表与集合的映射关系,下面就和Collection是一样的了。

方式二:使用多步查询

先查询部门id,再根据部门id查询员工信息

两个接口分别如下:

Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);
List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);

对应的映射文件如下

resultMap id="DeptAndEmpByStepOne" type="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps"
        select="com.atguigu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"

        column="dept_id">
<!--以dept_id为条件,我们是先查询部门的dept_id再根据部门的dept_id查询我要的emp的信息-->
        </collection>
    </resultMap>
    <select id="getDeptAndEmpByStepOne" resultMap="DeptAndEmpByStepOne">
        select*from t_dept where dept_id=#{deptId}
    </select>

<!--    List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);-->
    <select id="getDeptAndEmpByStepTwo" resultType="Emp">
        select *from t_emp where dept_id=#{deptId}
    </select>

这个没有什么创新,和前面也大同小异

七、动态sql

动态sql就是几个标签

标签一:if标签

if标签:通过if判断标签中的内容是否有效,即标签中的内容是否会拼接到SQL中

比方说,服务器获取到信息后,如果得到的是空表示初始状态,如果获取的是空字符串表示客户没有填写信息,那么通过if标签可以判断是不是要将获取的信息拼接到sql语句当中,比如说:

<!--    List<Emp> getEmpByCondition(Emp emp);根据条件查询员工信息-->
    <select id="getEmpByConditionOne" resultType="Emp">
        select * from t_emp where 
        <if test="empName!=null and empName != ''">
            语句emp_name = #{empName}
        </if>
        <if test="age!=null and age !=''">
<!-- 目标是为了拼接到我的Emp对象当中-->
            and age=#{age}
        </if>
        <if test="gender!=null and gender !=''">
            <!-- 目标是为了拼接到我的Emp对象当中-->
            and gender=#{gender}
        </if>
    </select>

表示如果字符串不是空对象或者不为空,那么才进行对sql的拼接,值得注意的是这边要手动添加and这一信息。

问题一:如果第一个emp_name是空,那么sql语句就变为

select * from t_emp where and 。。。。这显然有问题;

问题二:如果全是空那么,sql语句select * from t_emp where也有问题

这时可以添加1=1,然后if第一个标签中添加and即可,即:

<!--    List<Emp> getEmpByCondition(Emp emp);根据条件查询员工信息-->
    <select id="getEmpByConditionOne" resultType="Emp">
        select * from t_emp where 1=1
        <if test="empName!=null and empName != ''">
            and emp_name = #{empName}
        </if>
        <if test="age!=null and age !=''">
<!-- 目标是为了拼接到我的Emp对象当中-->
            and age=#{age}
        </if>
        <if test="gender!=null and gender !=''">
            <!-- 目标是为了拼接到我的Emp对象当中-->
            and gender=#{gender}
        </if>
    </select>

标签二:where标签,where标签有三个功能

作用一:自动生成where关键字

作用二:自动将多余的前面的and去掉,内容后多余的and没有办法去掉

作用三:where标签中没有任何一个标签成立,where中没有任何功能        

可以发现,运用where标签也可以解决上面的问题。

<select id="getEmpByConditionTwo" resultType="Emp">
    select *from t_emp
    <where>
            <if test="empName!=null and empName != ''">
                emp_name = #{empName}
            </if>
            <if test="age!=null and age !=''">
                <!-- 目标是为了拼接到我的Emp对象当中-->
                and age=#{age}
            </if>
            <if test="gender!=null and gender !=''">
                <!-- 目标是为了拼接到我的Emp对象当中-->
                and gender=#{gender}
            </if>
    </where>
</select>

标签三:trim标签

     prefix与suffix:在标签前面后者后面添加指定内容
     prefixOverWrides和suffixOverrides:在标签中内容前面或者后面去掉指定内容

比方说(这个代码表示前面接上where后面去掉and然后进行操作):

<select id="getEmpByCondition" resultType="Emp">
    select* from t_emp
    <trim prefix="where" suffixOverrides="and">
        <if test="empName!=null and empName != ''">
            emp_name = #{empName} and
        </if>
        <if test="age!=null and age !=''">
            <!-- 目标是为了拼接到我的Emp对象当中-->
             age=#{age} and
        </if>
        <if test="gender!=null and gender !=''">
            <!-- 目标是为了拼接到我的Emp对象当中-->
             gender=#{gender}
        </if>
    </trim>
</select>

标签四:choose...when...otherwise(if...else if...else)进行处理操作,

其实也就是switch。。。case结构

<!--    List<Emp>getEmpByChoose(Emp emp);-->
    <select id="getEmpByChoose" resultType="Emp">
        select *from t_emp
        <where>
            <choose>
                <when test="empName!=null and empName != ''">
                    emp_name = #{empName}
                </when>
                <when test="age!=null and age !=''">
                    age=#{age}
                </when>
                <when test="gender!=null and gender !=''">
                    gender=#{gender}
                </when>
            </choose>
        </where>
    </select>

标签四:forEach标签

Collection:设置要循环的数组或者集合
item:用一个数组表示数组或集合中的每一个数据
separator:用于设置每一次循环数据的分隔符
open:循环的所有内容,以什么开始
close:循环的所有内容,以什么结束

如下面所示:

<!--    void insertMoreEmp(@params(list)List<Emp> emps);-->
    <insert id="insertMoreEmp">
        insert into t_emp values
<!-- item 表示数组或者集合中的元素数据-->
        <foreach collection="list" item="emp" separator=",">
            (null,#{emp.empName},#{emp.age},#{emp.gender},null)
        </foreach>
    </insert>

<!--    void deleteMoreEmp(@Param("empIds") Integer[] empIds);-->
    <delete id="deleteMoreEmp">
        delete from t_emp where emp_id in
<!-- open和close用来设置左括号和右括号以什么开始-->
            <foreach collection="empIds" item="empId" separator="," open="(" close=")">
                #{empId}
            </foreach>
    </delete>

标签五:sql标签

所谓sql标签就是可以记录一段公共sql片段,在使用的地方通过include标签进行引入

比如说,如下所示:

<sql id="empColumns">
    emp_id,emp_name,age,gender,dept_id
</sql>

<include></include>标签,在需要引用的地方,进行引用

<select id="getEmpByCondition" resultType="Emp">
    select <include refid="empColumns"></include> from t_emp
    <trim prefix="where" suffixOverrides="and">
        <if test="empName!=null and empName != ''">
            emp_name = #{empName} and
        </if>
        <if test="age!=null and age !=''">
            <!-- 目标是为了拼接到我的Emp对象当中-->
             age=#{age} and
        </if>
        <if test="gender!=null and gender !=''">
            <!-- 目标是为了拼接到我的Emp对象当中-->
             gender=#{gender}
        </if>
    </trim>
</select>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值