Mybatis总结

一、映射文件

Ⅰ.映射文件参数处理

注意:当参数为一个map时可以直接通过#{key} 、${key}获取对应的值

1.单个参数

单个参数时mybatis不会做任何处理:

#{任意值} => 取出这个参数的值

①传入一个map

可以通过#{key}或者${key}获取对应的值

//定义接口
public Employee getEmpByMap(Map<String,Object> map);
<!-- 映射文件中使用-->
<select id="getEmpByMap" resultType="com.wuliaodebaozi.bean.Employee">
     select id,last_name lastName,gender,email,did from ${tableName} where id = ${id} and last_name = #{lastName}
</select>
//测试代码
    Map<String,Object> map = new HashMap<>();
    map.put("id",1);
    map.put("lastName","jerry");
    map.put("tableName","employee");
    Employee employee = employeeMapper.getEmpByMap(map);

注意:map里面的map可以通过xx.key获取,比如

//测试代码
    Map<String,Object> map = new HashMap<>();
	Map<String,Object> mapSon = new HashMap<>();
	mapSon.put("what",123);


    map.put("id",1);
    map.put("secondMap",mapSon);
    Employee employee = employeeMapper.getEmpByMap(map);

现在要获取what的值(123)就可以通过#{secondMap.waht}、${secondMap.waht}来获取

②传入一个POJO

如果传入单个java对象,mybatis会将这个java对象封装成一个map,key为属性名,value为属性值,然后在映射文件中取值就像传入一个map时一样取值

//定义接口
public void updateEmployee(Employee employee);
<!-- 映射文件-->
<update id="updateEmployee" parameterType="com.wuliaodebaozi.bean.Employee">
    update employee
        set last_name=#{lastName},email=#{email},gender=#{gender}
        where id=#{id}
</update>
//测试代码
	Employee employee = new Employee(null, "jerry", "jerry@qq.com", "1");
	employeeMapper.addEmp(employee);

2.多个参数

多个参数时mybatis会将这些参数封装成一个map,map的key为param1 … paramN:

此时就相当于传入了单个map 可以通过#{key}、${key}获取对应的值

①命名参数的key

​ 多个参数时,使用param1、pararm2很不方便需要给参数命名这个使用起来就会方便很多。

​ 【1】在接口中使用注解@Param(“参数名”) 来命名参数

​ 【2】在映射文件中引用这个命名的参数

​ 例如:

​ 定义接口时使用@Param注解给参数命名

public Employee getEmpByIdAndLastName

​		(@Param("id") Integer id, @Param("lastName") String lastName);

​ 映射文件使用这个命名的参数

<select id="getEmpByIdAndLastName" resultType="com.wuliaodebaozi.bean.Employee">
    select id,last_name lastName,gender,email,did from employee where id = #{id} and last_name = #{lastName}
</select>

3.内置参数

mybatis有两个内置参数_parameter和databaseid

_parameter:代表整个参数

​ 单个参数时:_parameter就是这个参数

​ 多个参数时:多个参数会被封装为一个map:_parameter就是代表这个map ===> 用于判断POJO对象是否 为空。可以通过#{ _parameter.key}、 ${ _parameter.key}获取对应的值

databaseId:如果配置了databaseIdProvider标签

​ databaseId就是代表当前数据库的别名

4.#{}和${}区别

#{}是以预编译的形式将参数设置到sql语句中

${}是直接将参数设置到sql语句中

==> 参数为字符串 #{}会自动添加引号,${}不会

注意:在一些无法使用#{}的地方可以使用${} => 数据库表名、升序、降序、按什么字段升序、降序

Ⅱ.映射文件查询结果集封装规则

1.resultType

mybatis自动封装 => 列名对应javaBean的属性名

①返回数据类型

​ 【1】返回单个数据类型

​ resultType写该数据类型的全类名或别名

​ 【2】返回该数据类型的集合(List)

​ resultType写该数据类型的全类名或别名

​ 注意:返回单个类型还是一个集合根据在接口中定义的返回值类型确定

public Employee selectEmp(int id);       //返回单个数据类型

public List<Employee> selectEmp(int id);  //返回一个集合
②返回map

​ 【1】返回单条记录的map

​ resultType写map,key是列名,value是对应的值

​ 【2】多条记录封装一个map

​ a.Map<Integer,Employee> : 键是这条记录的主键,值是这条记录封装后的java类型

​ b.使用@MapKey(“id”)告诉mybatis封装map时哪个属性作为map的key

​ c.resultType写map中该数据类型的全类名或别名

2.ResultMap

①自定义某个javaBean的封装规则
<!--    自定义某个JavaBean的封装规则
        type:自定义规则的java类型
        id:唯一标识,方便引用
-->
<resultMap id="MyEmp" type="com.wuliaodebaozi.bean.Employee">
<!--        指定主键列的封装规则
            id:定义主键会底层优化
            column:指定哪一列
            property:指定对应的javaBean属性
-->
        <id column="id" property="id"></id>
<!--        定义普通列的封装规则-->
        <result column="last_name" property="lastName"></result>
<!--        其他不指定的列会自动封装,我们只要写resultMap就把全部的映射规则都写上-->
        <result column="email" property="email"></result>
        <result column="gender" property="gender"></result>
    </resultMap>

id:唯一标识,方便引用

type:指定自定义规则的java类型

②关联查询结果集封装【关联单个对象】(javaBean里包含单个对象属性)
【1】联表查询
a. 级联属性封装结果
<!--
    场景一、查询Employee的同时,查出员工对应的部门
    Eployee ==== Department
    一个员工有与之对应的部门信息
-->
<!--
    级联查询:级联属性封装结果集
-->
    <resultMap id="MyDifEmp" type="com.wuliaodebaozi.bean.Employee">
        <id column="id" property="id"></id>
        <result column="lastName" property="lastName"></result>
        <result column="gender" property="gender"></result>
        <result column="did" property="dept.id"></result>
        <result column="departmentName" property="dept.departmentName"></result>
    </resultMap>

员工Employee对象包含Department对象可以将employee表和Department表一起关联查询出来,通过级联属性设置employee里面的department对象的属性

b. 使用association定义关联对象单个对象的封装规则
<!--    使用association定义关联单个对象的封装规则-->
    <resultMap id="MyDifEmp2" type="com.wuliaodebaozi.bean.Employee">
        <id column="id" property="id"></id>
        <result column="lastName" property="lastName"></result>
        <result column="gender" property="gender"></result>
<!--     association可以指定联合的javaBean对象
        property="dept" 指定哪个属性是联合的对象
        javaType:指定联合属性的java类型【不能省略】
-->
        <association property="dept" javaType="com.wuliaodebaozi.bean.Department">
            <id column="did" property="id"></id>
            <result column="departmentName" property="departmentName"></result>
        </association>
    </resultMap>

使用association定义属性对象的封装规则

【2】分步查询

使用association进行分步查询 ==> 调用其他查询方法

<select id="getDeptById" resultType="com.wuliaodebaozi.bean.Department">
    select did id,department_name departmentName from department where did = #{id}
</select>
<!--    使用association进行分步查询
        1.根据员工id查询员工信息
        2.根据员工信息中的did去部门表查出部门信息
        3.部门设置到员工里面
-->
    <resultMap id="MyempByStep" type="com.wuliaodebaozi.bean.Employee">
        <id column="id" property="id"></id>
        <result column="last_name" property="lastName"></result>
        <result column="email" property="email"></result>
        <result column="gender" property="gender"></result>
<!--     association定义关联对象的封装规则
         select:表明是调用select指定的方法查出的记过
         column:指定将那一列的值传给这个方法作为参数


         流程:使用select指定的方法(传入column这列的值作为方法的参数)查出结果,并封装property指定的对象属性
  -->
        <association property="dept" select="com.wuliaodebaozi.mapper.DepartmentMapper.getDeptById"
            column="did"></association>
    </resultMap>

使用association调用其他查询方法 property:封装的对象属性 select:其他的查询方法namespace+方法id colum:使用那列作为参数

注意:分步查询可以使用按需加载(懒加载),在全局配置文件中开启两个配置

<!--    可以使用延迟加载:(按需加载):(懒加载)
        Employee  ==>  Dept
        我们每次查询Employee对象的时候,都将一起查询出来
        部门信息在我们使用的时候再去查询
        分步查询的基础之上加上两个配置:
-->
<!--        显示的指定我们需要更改的值,即使它是默认的,防止版本更新带来的问题-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
③关联查询结果集封装【关联集合对象】(javaBean里包含集合对象属性)
【1】联表查询,将两张表一起查询出来

查询部门,Department 包含 List emps属性

将department表和employee表关联,在定义department的封装规则时使用collection定义List的封装规则

<!--
        collection嵌套结果集的方式,定义关联的集合类型元素的封装规则
-->

    <resultMap id="MyDept" type="com.wuliaodebaozi.bean.Department">
        <id column="did" property="id"></id>
        <result column="dept_name" property="departmentName"></result>
<!--        collection定义关联的集合类型的属性的封装规则
            ofType:指定集合里面元素的类型
-->
        <collection property="emps" ofType="com.wuliaodebaozi.bean.Employee">
<!--            定义集合里面元素的封装规则-->
            <id column="eid" property="id"></id>
            <result column="last_name" property="lastName"></result>
            <result column="email" property="email"></result>
            <result column="gender" property="gender"></result>
        </collection>

    </resultMap>
    <select id="getDeptByIdPlus" resultMap="MyDept">
        SELECT d.did did,d.department_name dept_name,
        e.id eid,e.last_name last_name,e.email email,e.gender gender
        FROM department d LEFT JOIN employee e ON d.did = e.did
        WHERE d.did = #{id}
    </select>
【2】分步查询,分两步查询

在定义List emps的封装规则是使用collection标签,调用查询员工的方法

a. property=“emps” 指定javaBean里集合元素的属性名

b. select 需要调用的查询方法

c. column 指定哪一列作为参数传入

<select id="getEmpsByDeptId" resultMap="MySimpleEmp">
    select * from employee where did = #{deptId}
</select>
<resultMap id="MyDeptStep" type="com.wuliaodebaozi.bean.Department">
    <id column="id" property="id"></id>
    <result column="departmentName" property="departmentName"></result>
    <collection property="emps" select="com.wuliaodebaozi.mapper.EmployeeMapperPlus.getEmpsByDeptId" column="id"></collection>
</resultMap>
<select id="getDeptByIdStep" resultMap="MyDeptStep">
    select did id,department_name departmentName from department where did = #{id}
</select>

3.数据库查询结果种类(1,n,1对1,1对n,n对n)

不论是resultType还是resultMap,mybatis都会根据接口处返回值判断当前是selectOne、selectList、selectMap

①mybatis根据resultType或resultMap将查询出来的结果集根据封装规则封装成单个或多个javaBean

②根据接口中定义的返回值类型,进行进一步封装,如果返回是List则将这些javaBean封装成List,如果是Map则封装成Map。但是如果返回单个对象而结果集有多个javaBean则报错

根据查询出来的结果集和resultType或resultMap封装规则 =初步封装> 单个或多个javaBean

根据接口定义的返回值类型 =再次封装> 单个、List或Map

在这里插入图片描述

结果集类型:

【1】封装成单个javaBean ===> Employee

public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private  String gender;
    }
idlast_namegenderemaildid
1jerry0123@qq.com1

【2】封装成多个javaBean ====> List

idlast_namegenderemaildid
1jerry0123@qq.com1
2jerry0123@qq.com2
3jerry0123@qq.com1

【3】多表联查封装成单个javaBean ====> Employee 包含 Department(一对一)

public class Employee {
        private Integer id;
        private String lastName;
        private String email;
        private  String gender;
    	private Department dept;
}
public class Department {
    private Integer id;
    private String departmentName;
}
idlast_namegenderemaildiddepartment_name
1jerry0123@qq.com1开发部

【4】多表联查封装成单个javaBean ====>Department ,并且每个Department里包含 List(即一个部门,里面包含这个部门里面所有的员工)(一对多)

public class Department {
    private Integer id;
    private String departmentName;

    private List<Employee> emps;
}
public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private  String gender;
    }
diddepartment_nameeidlast_nameemailgender
1开发部1jerryjerry@qq.com0
1开发部2jerryjerry@qq.com1
1开发部5jerryjerry@qq.com0

【5】多表联查封装成多个javaBean ====> List depts,并且每个Department里包含 List(即一个部门,里面包含这个部门里面所有的员工)(多对多)

diddepartment_nameeidlast_nameemailgender
1开发部1jerryjerry@qq.com0
1开发部2jerryjerry@qq.com1
1开发部5jerryjerry@qq.com0
2测试部3jerryjerry@qq.com0
2测试部4jerryjerry@qq.com1

Ⅲ.映射文件动态SQL

mybatis动态SQL主要概括为三大部分

【1】if 判断

【2】choose(when,otherwise):分支选择 带了break的swich-case

【3】trim 字符串截取(where(封装查询条件),set(封装修改条件))

【4】foreach遍历集合、数组、map

1.if

test=""里面为OGNL表达式,当表达式为true时,拼接if里面的字符串,否则舍弃掉里面的字符串,可以直接从参数中取值进行判断,不需要使用#{}

注意:里面的一些特殊字符比如& 在双引号中不能直接使用需要使用它的转义字符 & amp;

<!--    查询员工,要求:携带了哪个字段查询条件就带上这个字段的值-->
    <select id="getEmpsByConditonIf" resultType="com.wuliaodebaozi.bean.Employee">
        select * from employee
        where
        <!--test:判断表达式(OGNL)
           OGNL参照官方文档
           从参数中取值进行判断
           遇见特殊符号应该去写转义字符
           &&:特殊字符
        -->
            <if test="id!=null">
                and id=#{id}
            </if>
            <if test="lastName != null &amp;&amp; lastName != ''">
                and  last_name like #{lastName}
            </if>
            <if test="email != null and email.trim() != ''">
                and email = #{email}
            </if>
            <!-- OGNL会进行字符串与数字的转换判断 “0” == 0-->

            <if test="gender == 0 or gender == 1">
                and gender = #{gender}
            </if>  
    </select>

2.choose(when,otherwise)

这个类似于java中带了break的swich-case,它只会执行第一个判断为真的when

<!--  如果带了id就用id查,如果带了lastName 就用lastName查,只会进入其中一个  -->
    <select id="getEmpsByConditionChoose" resultType="com.wuliaodebaozi.bean.Employee">
        select  * from employee
        where
            <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>
    </select>

3.trim(where、set)

where:去掉标签中字符串前面多出的and和or

使用场景:在动态拼接查询条件时,可能第一个条件不满足要求导致后面的条件以and开始

<!--    查询员工,要求:携带了哪个字段查询条件就带上这个字段的值-->
    <select id="getEmpsByConditonIf" resultType="com.wuliaodebaozi.bean.Employee">
        select * from employee
        <where>
            <if test="id!=null">
                and id=#{id}
            </if>
            <if test="lastName != null &amp;&amp; lastName != ''">
                and  last_name like #{lastName}
            </if>
            <if test="email != null and email.trim() != ''">
                and email = #{email}
            </if>
            <!-- OGNL会进行字符串与数字的转换判断 “0” == 0-->

            <if test="gender == 0 or gender == 1">
                and gender = #{gender}
            </if>
        </where>
    </select>

set:去掉set标签中字符串后面多出的逗号

使用场景:在动态拼接更新语句时,可能最后一个条件不满足要求,从而导致倒数第二个更新后面多出一个逗号

 <update id="updateEmp">
        update 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}
    </update>

trim:字符串截取 ==> 为标签中的字符串拼接一个开始字符串、结束字符串,并且可以去掉标签中字符串开头或者末尾多出的字符串

prefix="":前缀,trim标签体中是整个字符串拼串后的结果,perfix给拼串后的整个字符串加一个前缀
prefixOverrides="" 前缀覆盖:去掉整个字符串前面多余的字符
suffix="“suffix给拼串后的整个字符串加一个后缀
suffixOverrides=”"后缀覆盖:去掉整个字符串后面多余的字符

<select id="getEmpsByConditonTrim" resultType="com.wuliaodebaozi.bean.Employee">
    select * from employee
    <!-- 后面多出的and或者or where标签不能解决
        prefix="":前缀,trim标签体中是整个字符串拼串后的结果
                perfix给拼串后的整个字符串加一个前缀
        prefixOverrides=""
               前缀覆盖:去掉整个字符串前面多余的字符
        suffix=""
                suffix给拼串后的整个字符串加一个后缀
        suffixOverrides=""
                后缀覆盖:去掉整个字符串后面多余的字符
    -->
    <!-- 自定义字符串截取规则 -->
    <trim prefix="where" suffixOverrides="and">
        <if test="id!=null">
            id=#{id} and
        </if>
        <if test="lastName != null &amp;&amp; lastName != ''">
            last_name like #{lastName} and
        </if>
        <if test="email != null and email.trim() != ''">
            email = #{email} and
        </if>
        <!-- OGNL会进行字符串与数字的转换判断 “0” == 0-->

        <if test="gender == 0 or gender == 1">
            gender = #{gender} and
        </if>
    </trim>
</select>

注意:where和set标签都可以用trim标签替代,只是where和set标签更见名知意。

4.foreach

foreach标签可以用来遍历参数里面的集合、数组、map

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

<select id="getEmpsByForeach" resultType="com.wuliaodebaozi.bean.Employee">
    select * from employee where id in
    <!--
        collection:指定需要遍历的集合
            list类型的参数会特殊处理封装在map中,map的key就叫list
        item:将当前遍历出的变量赋值给指定的变量
            #{变量名}就能取出变量值,也就是当前遍历出的元素
        separator:每个元素之间的分隔符
        open:遍历所有的结果后在前面拼接一个开始字符串
        close:遍历所有的结果后在后面拼接一个结束字符串
        index:索引,遍历list的时候index就是索引,item就是当前的值
                    遍历map的时候index表示的是map的key,item就是map的值

     -->
    <foreach collection="ids" item="item_id" separator="," open="(" close=")">
        #{item_id}
    </foreach>
</select>
历map的时候index表示的是当前元素的key,item就是当前元素的值

```xml
<select id="getEmpsByForeach" resultType="com.wuliaodebaozi.bean.Employee">
    select * from employee where id in
    <!--
        collection:指定需要遍历的集合
            list类型的参数会特殊处理封装在map中,map的key就叫list
        item:将当前遍历出的变量赋值给指定的变量
            #{变量名}就能取出变量值,也就是当前遍历出的元素
        separator:每个元素之间的分隔符
        open:遍历所有的结果后在前面拼接一个开始字符串
        close:遍历所有的结果后在后面拼接一个结束字符串
        index:索引,遍历list的时候index就是索引,item就是当前的值
                    遍历map的时候index表示的是map的key,item就是map的值

     -->
    <foreach collection="ids" item="item_id" separator="," open="(" close=")">
        #{item_id}
    </foreach>
</select>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值