动态SQL、缓存、resultMap连表、注解开发

一、动态sql

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

1.if

用于进行条件判断, test 属性用于指定判断条件. 为了拼接条件, 在 SQL 语句后强行添加 1=1 的恒成立条件。

映射文件(EmpMapper.xml)下:
 <!--if 当你传过来的参数符合下面if的条件时,则安下面的语句来执行,如果都不符合,就执行where 1=1-->
    <select id="selectIf" resultType="Emp" parameterType="Emp">
        select * from emp where 1 = 1
        <if test="empno != null and empno != '' ">and empno=#{empno}
        </if>

        <if test="ename != null and ename != '' ">and ename=#{ename}
        </if>
    </select>
接口下:
Emp selectIf(Emp emp);
测试类下:
Emp emp = new Emp();
emp.setEmpno(7369);
Emp emp1 = mapper.selectIf(emp);
System.out.println(emp1);

2.where

用于管理 where 子句. 有如下功能:

  • 如果没有条件, 不会生成 where 关键字
  • 如果有条件, 会自动添加 where 关键字
  • 如果第一个条件中有 and, 去除之
映射文件(EmpMapper.xml)下:
 <select id="selectWhere" resultType="Emp" parameterType="Emp">
        select * from emp
        <where>
            <if test="empno != null and empno != ''"> and empno=#{empno} </if>
            <if test="ename != null and ename != ''"> and ename=#{ename} </if>
        </where>
    </select>
接口下:
Emp selectWhere(Emp emps);
测试类下:
Emp emp = new Emp();
emp.setEmpno(7369);
emp.setEname("SMITH");
Emp emp1 = mapper.selectWhere(emp);
System.out.println(emp1);

3.choose…when…otherwise

这是一套标签, 功能类似于 switch…case…

映射文件(DeptMapper.xml)下:
 <!--根据部门地址和部门的名称查询部门信息-->
    <select id="selectByNameLoc" parameterType="Dept" resultType="Dept">
        select * from dept
        <where>
            <choose>
                <when test="dname!=null and dname!=''">
                    and dname = #{dname}
                </when>
                <when test="loc!=null and loc!=''">
                    and loc = #{loc}
                </when>
                <otherwise>
                    and 1=1
                </otherwise>
            </choose>
        </where>
    </select>
接口下:
List<Dept> selectByNameLoc(Dept dept);
测试类下:
//根据部门地址或者部门的名称查询部门信息
List<Dept> depts = mapper.selectByNameLoc(new Dept(null,"AAAA","ABC"));
depts.forEach(System.out::println);

4.set

用于维护 update 语句中的 set 子句,功能如下:

  • 满足条件时, 会自动添加 set 关键字
  • 会去除 set 子句中多余的逗号
  • 不满足条件时, 不会生成 set 关键字
映射文件(DeptMapper.xml)下:
<!-- 根据部门编号修改部门信息-->
    <update id="updateBySomething" parameterType="Dept">
        update dept
        <set>
            deptno=#{deptno},
            <if test="dname!=null and dname!=''">
                dname=#{dname},
            </if>

            <if test="loc!=null and loc!=''">
                loc=#{loc},
            </if>

        </set>
        where deptno=#{deptno}

    </update>
接口下:
Integer updateBySomething(Dept dept);
测试类下:
Integer integer = mapper.updateBySomething(new Dept(43, null, "ABC"));
System.out.println(integer);

5.trim

用于在前后添加或删除一些内容

  • prefix, 在前面添加内容
  • prefixOverrides, 从前面去除内容
  • suffix, 向后面添加内容
  • suffixOverrides, 从后面去除内容
映射文件(DeptMapper.xml)下:
<!-- 根据部门编号修改部门信息-->
    <update id="updateDeptByDeptno" parameterType="Dept">
        update dept
        /*由于加了后缀 bb 所以无法正常执行   */
        <trim prefix="set" prefixOverrides="a" suffix="bb" suffixOverrides=",">
                dname=#{dname},
        </trim>
        where deptno=#{deptno}
    </update>
接口下:
Integer updateDeptByDeptno(Dept dept);
Integer integer = mapper.updateDeptByDeptno(new Dept(43, "ZZZZ", "ABC"));
System.out.println(integer);

6.bind

用于对数据进行再加工, 用于模糊查询

映射文件(DeptMapper.xml)下:
<!--查询部门名称中包含 'A' 的部门信息-->
    <select id="selectLike" parameterType="Dept" resultType="Dept">
        select * from dept
        <where>
            <if test="dname!=null and dname!=''">
                <bind name="dname" value="'%' + dname + '%'" />
                    dname like #{dname}

            </if>
        </where>
    </select>
接口下:
List<Dept> selectLike(Dept dept);
测试类下:
List<Dept> depts = mapper.selectLike(new Dept(null, "A", null));
System.out.println(depts.size());

7.foreach

用于在 SQL 语句中遍历集合参数, 在 in 查询中使用

  • collection: 待遍历的集合
  • open: 设置开始符号
  • item: 迭代变量
  • separator: 项目分隔符
  • close: 设置结束符

前面已用过。

8.sql…include

sql用于提取 SQL 语句, include用于引用 SQL 语句

映射文件(DeptMapper.xml)下:
<!--公共的sql片段,可以被其他的标签包含-->
    <sql id="pubsql">
        deptno dno, dname,loc
    </sql>
<!--查询所有的部门信息-->
    <select id="selectAll" resultType="Dept">
        select
        /* 包含指定的sql片段*/
        <include refid="pubsql" />
         from dept
    </select>
接口下:
List<Dept> selectAll();
测试类下:
List<Dept> depts = mapper.selectAll();
depts.forEach(System.out::println);

二、Mybatis缓存机制(了解)

mybatis 也提供了对缓存的支持,分为一级缓存和二级缓存。但是在默认的情况下,只开启一级缓存。

1.一级缓存

  1. 默认开启. 线程级别的缓存, SqlSession 的缓存;
  2. 在一个 SqlSession 生命周期中有效. SqlSession 关闭,缓存清空;
  3. 在同一个 SqlSession 中, Mybatis 会把执行的方法和参数通过算法生成缓存的键值,将键值和结果存放在一个 Map 中,如果后续的键值一样,则直接从 Map 中获取数据;
  4. 不同的 SqlSession 之间的缓存是相互隔离的;
  5. 用一个 SqlSession,可以通过配置使得在查询前清空缓存;flushCache=“true”
  6. 任何的 UPDATE, INSERT, DELETE 语句都会清空缓存。

2.二级缓存

  1. 进程级别的缓存, SqlSessionFactory 的缓存
  2. 在一个SqlSessionFactory生命周期中有效. 可以在多个SqlSession 生命中期中共享.
  3. 默认关闭, 需要使用的时候, 要为某个命名空间开启二级缓存(在 mapper.xml 中配置cache).
  4. 由于在更新时会刷新缓存,因此需要注意使用场合:查询频率很高,更新频率很低时使用,即经常使用 select, 相对较少使用delete, insert, update。
  5. 缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响。但刷新缓存是刷新整个 namespace 的缓存,也就是你 update 了一个,则整个缓存都刷新了。
  6. 最好在「只有单表操作」的表的 namespace 使用缓存,而且对该表的操作都在这个namespace 中。否则可能会出现数据不一致的情况。
映射文件(DeptMapper.xml)下:
<!-- 开启二级缓存, 要求实体类进行序列化 -->
<cache/>

三、列名和属性名不一致问题

1. 给列取别名

查询时, 可以通过列别名的方式将列名和属性名保持一致,继续使用自动映射, 从而解决该问题. 但是较为麻烦。

2.使用resultMap

resultMap用于自定义映射关系, 可以由程序员自主制定列名和属性名的映射关系. 一旦使用resultMap, 表示不再采用自动映射机制。

映射文件(EmpMapper.xml)下:
<resultMap id="empmap" type="Emp">
    <!-- 需要写全了-->
    <!--id标签一般就用于主键,不用也行  property:类的属性名    column:表中的字段名-->
    <id column="empno" property="no"/>
    <result column="ename" property="ename"/>
    <result column="mgr" property="mgr"/>
</resultMap>

<select id="selectAllMap" resultMap="empmap" >
    select * from emp
</select>
接口中:
List<Emp> selectAllMap();
测试类下:
List<Emp> empList = mapper.selectAllMap();
empList.forEach(System.out::println);

四、关系映射查询

1.resultMap 的关联方式实现多表查询(一对一|多对一)

映射文件(EmpMapper.xml)下:
<!-- emp对象和表的映射-->
	<!--查询员工信息以及其对应的部门信息-->
    <resultMap id="empdept" type="Emp">
     <!--id标签一般就用于主键,不用也行  property:类的属性名    column:表中的字段名-->
        <id property="no" column="empno"/>
        <result column="ename" property="ename"/>
        <result column="mgr" property="mgr"/>
        <!--emp 类中的dept属性  和表对象的映射-->
        <association property="deptInfo" javaType="Dept">
            <id property="dno" column="deptno"/>
            <result property="dname" column="dname"/>
        </association>

    </resultMap>

    <select id="selectEmpDeptInfo" resultMap="empdept">
        select * from emp join dept on emp.deptno=dept.deptno
    </select>
接口下:
List<Emp> selectEmpDeptInfo();
测试类下:
// 查询员工信息以及其对应的部门信息
List<Emp> emps = mapper.selectEmpDeptInfo();
emps.forEach(System.out::println);

2.resultMap 的关联方式实现多表查询(一对多)

collection:集合。

映射文件(DeptMapper.xml)下:
<!--查询所有部门信息以及其对应的员工信息-->
    <resultMap id="deptemp" type="Dept">
        <!--id标签一般就用于主键,不用也行  property:类的属性名    column:表中的字段名-->
        <id property="dno" column="deptno"/>
        <result property="dname" column="dname"/>
        <result property="loc" column="loc"/>
        <!-- collection:集合   property:哪个属性是集合   ofType:集合中放的是什么对象  javaType:集合类型-->
        <collection property="emps"  ofType="Emp" javaType="list">
            <id property="no" column="empno"/>
            <result property="ename" column="ename"/>
        </collection>

    </resultMap>

    <select id="selectDeptEmp" resultMap="deptemp">
        select * from dept join emp on dept.deptno=emp.deptno
    </select>
接口下:
List<Dept> selectDeptEmp();
测试类下:
List<Dept> depts = mapper.selectDeptEmp();
depts.forEach(System.out::println);

五、注解开发

使用注解一般用于简化配置文件. 但是, 注解有时候也不是很友好(有时候反而更麻烦), 例如动态 SQL等,所以注解和配置文件可以配合使用。

一些简单的增删改查,使用注解更简单,此时不需要映射文件。

/*@Select -> 用来进行查询*/

    @Select("select * from emp")
    List<Emp> selectAll();

    @Update("update emp set ename=#{ename} where empno=#{no}")
    Integer updateEmp(Emp emp);



    @Delete("delete from emp where empno=#{non}")
    Integer deleteEmp(Integer no);

    @Insert("insert into emp(empno, ename) values(#{param1}, #{param2})")
    Integer insertEmp( Integer empno, String ename);
SqlSession session = MyBatisUtils.getSession(true);
EmpMapper mapper = session.getMapper(EmpMapper.class);
/*List<Emp> emps = mapper.selectAll();
emps.forEach(System.out::println);*/

/*Emp emp = new Emp();
emp.setNo(8899);
emp.setEname("ABCD");
System.out.println(mapper.updateEmp(emp));*/

System.out.println(mapper.insertEmp(8899,"LiLei"));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值