day3 - mybatis基本查询映射配置&更新映射和缓存机制&查询结果的封装和高级映射&动态SQL

主要内容
1. 应用<select>元素实现数据查询
2. <insert><update><delete>元素更新数据
3. 应用<sql>元素实现重用,应用缓存设置
4. 查询返回结果的封装处理
5. 动态SQL应用

1. 应用<select>元素实现数据查询

select元素用来从数据库中查询数据结果,一个最简单的select实现方式如下所示:


1.1 使用select元素实现数据查询

1.1 <select>元素属性说明

select元素属性规范查询中的动作。诸如,如何传递查询参数,映射返回结果,是否使用缓存,查询超时限定等特性。

<select>常用的属性

1.2 select常用的属性

1.2 使用parameterType设置参数

  • parameterType是int, resultType是某个类的例子
    <select id="findStuByAge" resultType="stu" parameterType="int">
        <![CDATA[select * from student where age > #{age}]]>
    </select>

代码实现

    public List<Student> findStuByAge(int age){
        return SqlSessionFactoryManager.getSqlSession().selectList("students.findStuByAge",age);
    }
  • parameterType是string, resultType是map的例子
    <select id="findStuByEmail" resultType="map" parameterType="string">
        <![CDATA[select * from student where email = #{email}]]>
    </select>

代码实现

    public Map<String, Object> findStuByEmail(){
        String email = "123@163.com";
        return SqlSessionFactoryManager.getSqlSession().selectOne("students.findStuByEmail",email);
    }
  • parameterType是map, resultType是某个类的例子
    <select id="findStuByArgs" resultType="stu" parameterType="map">
        <![CDATA[select * from student where email <> #{email} and age > #{age}
        and birth > #{birth}
        ]]>
    </select>

代码实现

    public List<Student> findStuByArgs(){
        String email = "123@163.com";
        int age = 18;
        String birth = "1900-01-01";
        Map<String, Object> map = new HashMap<>();
        map.put("email",email);
        map.put("age",age);
        map.put("birth",birth);
        return SqlSessionFactoryManager.getSqlSession()
                .selectList("students.findStuByArgs",map);
    }

2<insert><update><delete>元素更新数据

2.1 <insert><update>通用属性

除了具有<select>等元素的通用属性外,<insert>和<update>还具有以下相同常用属性:


2.1 insert&update通用属性

keyProperty和keyColumn相互对应。

2.2 使用<insert>元素映射insert语句

保存一个department表的信息到数据库中
mapper.xml中的内容:

    <insert id="saveDepartment" parameterType="map" keyColumn="ID"
            keyProperty="id" statementType="PREPARED">
        <![CDATA[insert into department(id, name, code, newdate, descs)
            values(#{id},#{name},#{code},#{newdate},#{descs})]]>
    </insert>

代码实现:

    public int saveDepartment(Map<String, Object> map){
        System.out.println("执行保存");
        //获取sqlSession实例
        SqlSession sqlSession = SqlSessionFactoryManager.getSqlSession();
        int res = sqlSession.insert("deps.saveDepartment",map);
        sqlSession.commit();
        sqlSession.close();
        return res;
    }

2.3 使用<update>元素映射update语句

根据指定id更新数据库的表
mapper.xml中的内容:

    <update id="updateDepartmentById" parameterType="map" flushCache="true" statementType="PREPARED">
        <![CDATA[
            update department
            set descs = #{descs}, name = #{name}
            where id = #{id}]]>
    </update>

代码实现:

    /**
     * 实现按照部门id更新部门信息
     * @param map 部门map
     * @return
     */
    public int updateDepartmentById(Map<String, Object> map){
        System.out.println("执行修改");
        //获取sqlSession实例
        SqlSession sqlSession = SqlSessionFactoryManager.getSqlSession();
        int res = sqlSession.update("deps.updateDepartmentById",map);
        sqlSession.commit();
        sqlSession.close();
        return res;
    }

2.4 使用<delete>元素映射delete语句

根据给定的id删除department的内容
mapper.xml中的内容:

    <delete id="removeDepById" parameterType="string" flushCache="true" statementType="PREPARED">

        <![CDATA[
            delete from department
            where id = #{id}]]>
    </delete>

代码实现:

    /**
     * 按照指定的部门id删除此部门
     * @param depid 部门id
     * @return int
     */
    public int removeDepById(String depid){
        System.out.println("执行删除");
        //获取sqlSession实例
        SqlSession sqlSession = SqlSessionFactoryManager.getSqlSession();
        int res = sqlSession.delete("deps.removeDepById", depid);
        sqlSession.commit();
        sqlSession.close();
        return res;
    }

3.应用<sql>元素实现重用,应用缓存设置

3.1 <sql>元素实现重用

//定义一个重复使用的sql语句块

    <!--可重用的sql块,可以被当前映射中任何select, update及insert delete应用-->
    <sql id="DEPCommons">
        id, name, code, newdate, descs </sql>

//其他语句中调用

    <!--使用include引用sql元素不能使用常量语义符号包围, 否则无法进行解析-->
    <select id="queryDepList" resultType="dep" fetchSize="3">
        select <include refid = "DEPCommons"/> from department limit 0,3;
        <!--<![CDATA[select * from department limit 0,3;]]>-->
    </select>

3.2 应用缓存设置

数据缓存可以增加数据的访问操作效率,myBatis提供了设置sql的缓存策略和在sql映射中引用缓存策略。
myBatis使用cache元素在sql映射中设置缓存策略及使用ref-cache引用缓存策略。

3.2.1 myBatis缓存机制
3.1 myBatis缓存机制

myBatis一级缓存
一级缓存中每个SqlSession独享缓存数据

导致一级缓存查询失败的因素

3.2 myBatis一级缓存查询失败的因素

myBatis二级缓存
二级缓存中每个mapper中SqlSession会共享缓存数据

设置sql缓存

3.3.1 设置sql缓存

mybatis提供的几种缓存策略类型:

3.3.1 mybatis提供的几种缓存策略类型

应用缓存

cache-ref元素实现从一个mapper中引用当前的mapper中的缓存策略并应用。


3.3.2 应用缓存

导致二级缓存查询失败的原因

3.3.3 导致二级缓存查询失败的原因

二级缓存的缺陷

3.4 二级缓存的缺陷.png

缓存策略

使用第三方专业缓存工具代替myBatis二级缓存[Ehcache, Redis]

4. 查询返回结果的封装处理

myBatis通常在映射<select>元素执行sql使用returnType设置返回结果类型,有时需要对查询返回结果进行特殊处理;<select>元素提供了returnMap属性为查询返回结果进行处理的更灵活方式。
returnMap属性是对sql映射中某个returnMap元素的引用,而returnMap元素的定义决定了如何处理查询返回结果。

4.1 resultMap基本映射应用

Q: 数据库表student列名称和Student.Java类型属性名称不匹配,导致无法直接使用returnType指定为Student Java类型
S: 使用resultMap元素自定义返回结果的处理并映射记录行为Student Java类型,使用resultMap属性设置引用resultMap元素。
E:

    <!--使用列标签与实体bean属性保持一致达到自动映射的目的-->
    <select id="queryProductList" resultType="pro" useCache="true" statementType="PREPARED">
        <![CDATA[
        select id proId,code proCode,name proName,price proPrice,quality proQuantity,descs proDescs from product;
        ]]>
    </select>

    <resultMap id="ProMapping" type="pro" autoMapping="false">
        <id column="ID" property="proId" javaType="string" jdbcType="VARCHAR"/>
        <result column="CODE" property="proCode" javaType="string" jdbcType="VARCHAR"/>
        <result column="NAME" property="proName" javaType="string" jdbcType="VARCHAR"/>
        <result column="PRICE" property="proPrice" javaType="double" jdbcType="DOUBLE"/>
        <result column="QUALITY" property="proQuantity" javaType="integer" jdbcType="INTEGER"/>
        <result column="DESCS" property="proDescs" javaType="string" jdbcType="VARCHAR"/>
    </resultMap>

resultMap和resultType封装过程中只会有一个存在

4.2 resultMap元素说明

4.2.1 resultMap属性
4.2.1 resultMap元素属性
4.2.2 resultMap子元素
4.2.2 resultMap元素子元素
  • 高级复杂结果关联映射(一对多):collection的使用

使用resultMap元素映射复杂的一对多关联

    <select id="structTreeMap" resultMap="dep_emp_sal_map" statementType="PREPARED">
        <![CDATA[
        select d.id did, d.name dname, e.id eid, e.name ename,
               s.id sid, s.should, s.actual, s.mapYearMon
        from department d inner join emp e on d.id = e.DEPID
                          inner join salary s on e.id = s.empId;
        ]]>
    </select>

    <!--使用resultMap元素映射复杂的一对多关联-->
    <resultMap id="dep_emp_sal_map" type="dep" autoMapping="false">
        <id column="did" property="id" javaType="string" jdbcType="VARCHAR"/>
        <result column="dname" property="name" javaType="string" jdbcType="VARCHAR"/>
        <collection property="employeeList" autoMapping="false" ofType="emp">
            <id column="eid" property="id" javaType="string" jdbcType="VARCHAR"/>
            <result column="ename" property="name" javaType="string" jdbcType="VARCHAR"/>
            <collection property="salaryList" ofType="sal" autoMapping="false">
                <id column="sid" property="id" javaType="string" jdbcType="VARCHAR"/>
                <result column="should" property="should" javaType="integer" jdbcType="INTEGER"/>
                <result column="actual" property="actual" javaType="integer" jdbcType="INTEGER"/>
                <result column="mapYearMon" property="mapYearMon" javaType="date" jdbcType="DATE"/>
            </collection>
        </collection>
    </resultMap>

使用resultMap实现关联映射,实体数据使用map进行封装,避免定义更多的VO类

    <!--将一对多关联数据实体映射为map-->
    <select id="structTreeMap2" resultMap="depAndempAndsalAndmap" statementType="PREPARED">
        <![CDATA[
        select d.id did, d.name dname, e.id eid, e.name ename,
               s.id sid, s.should, s.actual, s.mapYearMon
        from department d inner join emp e on d.id = e.DEPID
                          inner join salary s on e.id = s.empId;
        ]]>
    </select>

    <!--使用resultMap元素映射复杂的一对多关联,实体数据使用Map进行封装,减少使用实体类-->
    <resultMap id="depAndempAndsalAndmap" type="treeMap" autoMapping="false">
        <id column="did" property="id" javaType="string" jdbcType="VARCHAR"/>
        <result column="dname" property="name" javaType="string" jdbcType="VARCHAR"/>
        <collection property="employeeList" autoMapping="false" ofType="treeMap">
            <id column="eid" property="id" javaType="string" jdbcType="VARCHAR"/>
            <result column="ename" property="name" javaType="string" jdbcType="VARCHAR"/>
            <collection property="salaryList" ofType="treeMap" autoMapping="false">
                <id column="sid" property="id" javaType="string" jdbcType="VARCHAR"/>
                <result column="should" property="should" javaType="integer" jdbcType="INTEGER"/>
                <result column="actual" property="actual" javaType="integer" jdbcType="INTEGER"/>
                <result column="mapYearMon" property="mapYearMon" javaType="date" jdbcType="DATE"/>
            </collection>
        </collection>
    </resultMap>

提示: id元素是嵌套映射中非常重要的角色,通常必须要映射它,如果不使用id作为标识结果,性能会有很大损耗。

  • 高级复杂结果关联映射(一对一): myBatis提供resultMap元素的association子元素实现一对一关联映射
  1. 使用association元素的select属性指向一条sql查询语句描述如何封装结果
  2. 使用association元素的resultMap属性指向association元素描述如何封装结果(效率高)

使用association元素的select属性指向一条sql查询语句描述如何封装结果

    <!-- 查询员工 -->
    <select id="findEmpAndDoc" resultMap="findEmpMap" statementType="PREPARED">
        select  * from emp 
    </select>

    <resultMap id="findEmpMap" type="emp" autoMapping="false">
        <id column="id" javaType="string" jdbcType="VARCHAR" property="id"/>
        <result column="name" javaType="string" jdbcType="VARCHAR" property="name"/>
        <!--column指定应该如何进行映射-->
        <association property="doc" autoMapping="false" column="id" javaType="doc"
                     select="findDocMap"/>
    </resultMap>

    <!--查询档案-->
    <select id="findDocMap" resultType="doc" parameterType="string" statementType="PREPARED">
        select  * from document where empid = #{empid};
    </select>

使用association元素的resultMap属性指向association元素描述如何封装结果(效率高, 仅仅去数据库之中查询一次)

    <!-- 查询员工对象和对应的档案对象集合 -->
    <select id="findEmployeeAndDocument" resultMap="findEmpMap2" statementType="PREPARED">
        select e.id eid,e.name, d.id did, d.number from emp e inner join document d on
            e.id = d.empid;
    </select>

    <!--映射员工查询返回结果-->
    <resultMap id="findEmpMap2" type="emp" autoMapping="false">
        <id column="eid" javaType="string" jdbcType="VARCHAR" property="id"/>
        <result column="name" javaType="string" jdbcType="VARCHAR" property="name"/>
        <association property="doc" javaType="doc" autoMapping="false"
                     resultMap="docMap" column="empid"/>
    </resultMap>

    <!--映射用户档案查询返回结果-->
    <resultMap id="docMap" type="doc" autoMapping="false">
        <id column="did" javaType="string" jdbcType="VARCHAR" property="id"/>
        <result column="number" javaType="string" jdbcType="VARCHAR" property="number"/>
    </resultMap>

5. 动态SQL应用

5.1 动态SQL应用

5.1 if

if元素是构成动态SQL语句非常重要的和使用比较频繁的元素,它表示执行一个逻辑判断,如果为true则执行if元素之内的内容,if元素有唯一的一个test属性用来接收一个布尔表达式,if经常用来组织where语句的连接生成

    <!--动态sql if的使用-->
    <select id="queryEmpListByGender" parameterType="int" resultType="emp" statementType="PREPARED">
        select id,name,birth,phone from emp
        <if test="'gender' != null">
            where gender = #{gender}
        </if>
    </select>

    <!--动态sql if的使用2-->
    <select id="queryEmpListByMap" parameterType="map" resultType="emp" statementType="PREPARED">
        select id,name,birth,phone from emp
        <if test="gender != null">
            where gender = #{gender}
        </if>
        <if test="name != null">
            and name like concat(#{name},"%")
            /*and name like '${name}%'*/
        </if>

    </select>

5.2 choose, when, otherwise

choose when otherwise类似于Java中的switch分支语句

    <!--choose when otherwise 动态sql-->
    <select id="queryEmpListByMap2" parameterType="map" resultType="emp" statementType="PREPARED">
        select id,name,birth,phone from emp where 1 = 1
        <choose>
            <when test="gender != null">and gender = #{gender}</when>
            <when test="name != null">and name not like '${name}%'</when>
            <when test="start != null and ends != null">
                and birth between #{start} and #{ends}
            </when>
            <otherwise>
                <if test="id != null">
                    and id = #{id}
                </if>
            </otherwise>
        </choose>
    </select>

5.3 trim, where, set

5.3.1 where

where元素用来代替用户手写的where sql关键字,它基本可以解决没有给定条件时而出现错误sql语法
where元素能够知道如果它包含的标签中有返回值的话,它就插入一个where, 如果标签返回的内容以AND或OR开头的,则它会剔除掉

示例:

    <!--动态sql 使用where元素代替手写where 避免手写where出错-->
    <select id="queryEmpListByMap3" parameterType="map" resultType="emp" statementType="PREPARED">
        select id,name,birth,phone from emp
        <where>
            <choose>
                <when test="gender != null">and gender = #{gender}</when>
                <when test="name != null">and name not like '${name}%'</when>
                <when test="start != null and ends != null">
                    and birth between #{start} and #{ends}
                </when>
                <otherwise>
                    <if test="id != null">
                        and id = #{id}
                    </if>
                </otherwise>
            </choose>
        </where>
    </select>
5.3.2 trim

trim元素可以用来代替where set等元素设置自定义动态sql语句,它有三个属性:
prefix: 指定前缀
suffix: 指定后缀
prefixOverrides: 设置分隔符(空格也属于分隔符之列)

示例:

    <!--动态sql trim 元素替代 where-->
    <select id="queryEmpListByMap4" parameterType="map" resultType="emp" statementType="PREPARED">
        select id,name,birth,phone from emp
        <trim prefix="where" prefixOverrides="and|or">
            <if test="gender != null">gender = #{gender}</if>
            <if test="name != null">and name like concat(#{name},'%')</if>
        </trim>
    </select>
5.3.3 set

set元素用来实现update语句的更新,它取代set关键字设置更新列信息。

示例:

    <!--使用set元素代替手写set更新sql语句关键字-->
    <update id="modifyEmployee" parameterType="emp" statementType="PREPARED">
        update emp
        <set>
            <if test="name != null">name = #{name},</if>
            <if test="gender != null">gender = #{gender},</if>
            <if test="address != null">address = #{address}</if>
        </set>
        where id = #{id}
    </update>

5.4 foreach

foreach是一个迭代功能的动态sql元素,通常在条件包含in或not in时使用其填充条件。
MyBatis会自动将有序集合及数组包装成一个Map处理,并使用它的名称作为key。List实例将使用"list"作为键,数组实例以"array"作为键。

示例:

    <!--使用foreach迭代参数集合-->
    <select id="queryEmpListForAddress" resultType="emp" statementType="PREPARED">
        select * from emp where address in
            <foreach collection="list" item="ele" index="index" separator=","
            open="(" close=")">
                #{ele}
            </foreach>
    </select>

    <!--使用foreach迭代参数集合(多参数)-->
    <select id="queryEmpListForAddress2" resultType="emp" parameterType="map" statementType="PREPARED">
        select * from emp where
        birth between #{startTime} and #{endTime} and address in 
        <foreach collection="addList" index="index" item="ele" separator=","
                 open="(" close=")">
            #{ele}
        </foreach>
    </select>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容