mybatis

动态SQL

1. If标签

  		 <if test="字段名 条件判断">
            and 列名=#{字段名}
        </if>
  		<if test="empno != null">
            and empno =#{empno}
        </if>

2. where标签

	<where>
        <if test="empno != null">
            and empno= #{empno}
        </if>
        <if test="ename != null and ename != ''">
            and ename= #{ename}
        </if>
    </where>
可去除 不正确的and 
例如: where and ename= #{ename}
会修正为: where  ename= #{ename}

3 . Set标签

<update id="方法名" >
    update 表名
	<set>
        <if test="ename != null and ename != '' ">
            , ename =#{ename}
        </if>
        <if test="job != null and ename != '' ">
            , job =#{job}
        </if>
      </set>
  </update>
可去除 不正确的 ','
例如: set , ename= #{ename}
会修正为: set ename= #{ename}

4. Trim标签

 <trim prefix=" <trim prefix="where" prefixOverrides="and" suffix="" suffixOverrides="">
            <if test="deptno!= null">
                DEPTNO = #{deptno}
            </if>
            <if test="dname!= null and dname!='' ">
                and DNAME=#{dname}
            </if>
            <if test="loc != null and loc!=''">
                and Loc =#{loc}
            </if>
        </trim>" prefixOverrides="and" suffix="" suffixOverrides="">
            <if test="deptno!= null">
                DEPTNO = #{deptno}
            </if>
            <if test="dname!= null and dname!='' ">
                and DNAME=#{dname}
            </if>
            <if test="loc != null and loc!=''">
                and Loc =#{loc}
            </if>
        </trim>

prefix : 前面填充内容 prefixOverrides 前面去除内容
suffix :后面填充内容 suffixOverrides 后面去除内容
where和set标签就是基于这个实现的

5. Bind标签

在这里插入图片描述

用于模糊查询使用,也可以使用 concat(“%”,#{字段名},“%”)进行拼接

6. Sql标签

<sql id="empColumn">empno,ename,job,mgr,hiredate,sal,comm,deptno</sql>
<sql id="baseSelect">select <include refid="empColumn"/>from emp</sql>

<!--List<Emp> findByCondition(Emp emp);-->
<select id="findByCondition" resultType="emp">
    <include refid="baseSelect"></include>
  </select>

通过<include refid = :“sqlId”/> 来引入上面定义的sql

7. Foreach标签

<foreach collection="list" separator="," open="(" close=")" item="deptno">
         #{deptno}
  </foreach>

collection : 参数类型,可参考mybatis官网
separator :分隔符
open: 前缀
close:后缀
item : 元素名

8.Choose标签

 <where>
        <choose>
            <when test="empno != null">
                and empno= #{empno}
            </when>
            <when test="ename != null and ename != ''">
                and ename= #{ename}
            </when>
             <otherwise>      
             </otherwise>
          </choose>
   </where>

相当于switch,满足一个就不会往下执行别的判断了,如果都不满足会走默认的

MyBatis实现多表查询

  1. 关联查询
  • 手动处理映射关系resultMap
<mapper namespace="com.xx.mapper.EmpMapper">
    <!--手动处理数据库查询字段和封装实体类属性之间的映射关系
    1 主键一般使用id属性
    2 当属性名和查询出的数据表字段名相同 可以不写映射关系
    -->
    <resultMap id="empMap" type="emp">
        <!--<id property="empno" column="empno"></id>-->
        <result property="name" column="ename"></result>
        <result property="job" column="job"></result>
        <result property="sal" column="sal"></result>
        <result property="hiredate" column="hiredate"></result>
        <result property="mgr" column="mgr"></result>
        <result property="comm" column="comm"></result>
        <result property="deptno" column="deptno"></result>
    </resultMap>
    <select id="findByEmpno" resultMap="empMap" >
        select * from emp where empno =#{empno}
    </select>
</mapper>
  • 一对一关联查询
<mapper namespace="com.xxx.mapper.EmpMapper">


    <!--Emp findEmpJoinDeptByEmpno(int empno);-->
    <resultMap id="empJoinDept" type="emp">
        <!--设置emp本身的八个属性的映射关系-->
        <id property="empno" column="empno"></id>
        <result property="ename" column="ename"></result>
        <result property="job" column="job"></result>
        <result property="sal" column="sal"></result>
        <result property="hiredate" column="hiredate"></result>
        <result property="mgr" column="mgr"></result>
        <result property="comm" column="comm"></result>
        <result property="deptno" column="deptno"></result>
        <!--
        association 处理一对一
        封装一对一信息关系的标签
        property  emp类的属性名
        javaType  用哪个类的对象给属性赋值
        -->
        <association property="dept" javaType="dept">
            <id column="deptno" property="deptno"></id>
            <result column="dname" property="dname"></result>
            <result column="loc" property="loc"></result>
        </association>

    </resultMap>

    <select id="findEmpJoinDeptByEmpno" resultMap="empJoinDept" >
        select * from
        emp e
        left join dept  d
        on e.deptno =d.deptno
        where empno = #{empno}
    </select>


</mapper>
  • 一对多关联查询
<mapper namespace="com.xxx.mapper.DeptMapper">
    <!--Dept findDeptJoinEmpsByDeptno(int deptno);-->
    <resultMap id="deptJoinEmps" type="dept">
        <id column="deptno" property="deptno"></id>
        <result column="dname" property="dname"></result>
        <result column="loc" property="loc"></result>
        <!--处理一对多关系的标签-->
        <collection property="empList" ofType="emp" >
            <!--设置emp本身的八个属性的映射关系-->
            <id property="empno" column="empno"></id>
            <result property="ename" column="ename"></result>
            <result property="job" column="job"></result>
            <result property="sal" column="sal"></result>
            <result property="hiredate" column="hiredate"></result>
            <result property="mgr" column="mgr"></result>
            <result property="comm" column="comm"></result>
            <result property="deptno" column="deptno"></result>
        </collection>
    </resultMap>


    <select id="findDeptJoinEmpsByDeptno" resultMap="deptJoinEmps">
        select * from dept d left join emp e on d.deptno =e.deptno where d.deptno =#{deptno}
    </select>


</mapper>
  • 多对多关联查询
<mapper namespace="com.xxx.mapper.ProjectMapper">

    <!--Project findProjectJoinEmpsByPid(int pid);-->
    <resultMap id="projectJoinEmps" type="project">
        <id column="pid" property="pid"></id>
        <result column="pname" property="pname"></result>
        <result column="money" property="money"></result>
        <!--一对多 集合属性 collection-->
        <collection property="projectRecords" ofType="projectRecord">
            <id column="empno" property="empno"></id>
            <id column="pid" property="pid"></id>
            <!--一对一 -->
            <association property="emp" javaType="emp">
                <id property="empno" column="empno"></id>
                <result property="ename" column="ename"></result>
                <result property="job" column="job"></result>
                <result property="sal" column="sal"></result>
                <result property="hiredate" column="hiredate"></result>
                <result property="mgr" column="mgr"></result>
                <result property="comm" column="comm"></result>
                <result property="deptno" column="deptno"></result>
            </association>
        </collection>

    </resultMap>

    <select id="findProjectJoinEmpsByPid"  resultMap="projectJoinEmps">
        select * from
        project p
        left join projectrecord pr
        on p.pid = pr.pid
        left join emp e
        on e.empno = pr.empno
        where p.pid= #{pid}
    </select>

</mapper>
  1. 级联查询
    级联查询,顾名思义,就是利于数据库表间的外键关联关系进行自动的级联查询操作。使用MyBatis实现级联查询,除了实体类增加关联属性外,还需要在映射文件中进行配置。
  • 立即加载
<mapper namespace="com.xxx.mapper.DeptMapper">
    <!--Dept findDeptByDeptno(int deptno);
    select="com.msb.mapper.EmpMapper.findEmpsByDeptno" 调用的另一个SQL语句
    javaType="list"  实体类的属性数据类型
    column="deptno"  给另一个SQL语句传入的参数列
    jdbcType="INTEGER" 参数对应JDBC的数据类型
    fetchType="eager"  加载方式 eager 积极加载  lazy延迟加载-->
    <resultMap id="deptJoinEmps" type="dept">
        <id property="deptno" column="deptno"></id>
        <result property="dname" column="dname"></result>
        <result property="loc" column="loc"></result>

        <collection property="empList"
                    select="com.msb.mapper.EmpMapper.findEmpsByDeptno"
                    javaType="list"
                    column="deptno"
                    jdbcType="INTEGER"
                    fetchType="eager"
        >
        </collection>

    </resultMap>

    <select id="findDeptByDeptno" resultMap="deptJoinEmps">
        select * from dept where deptno =#{deptno}
    </select>
</mapper>
  • 延迟加载
    第一步:全局开关:在sqlMapConfig.xml中打开延迟加载的开关。配置完成后所有的association和collection元素都生效
<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="true"/>
</settings>

lazyLoadingEnabled:是否开启延迟加载。是Mybatis是否启用懒加载的全局开关。当开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态
aggressiveLazyLoading:当开启时,任何方法的调用都会懒加载对象的所有属性。否则,每个属性会按需加载,
第二步:分开关:指定的association和collection元素中配置fetchType属性。eager:表示立刻加载;lazy:表示延迟加载。将覆盖全局延迟设置。

  • 多表查询总结与扩展
    在这里插入图片描述
    在这里插入图片描述

ResultType和ResultMap使用场景
1)如果你做的是单表的查询并且封装的实体和数据库的字段一一对应 resultType
2)如果实体封装的属性和数据库的字段不一致 resultMap
3)使用N+1级联查询的时候 resultMap
4)使用的是多表的连接查询 resultMap

一对一关联映射的实现
1)实例:学生和学生证、雇员和工牌
2)数据库层次:主键关联或者外键关联(参看之前内容)
3)MyBatis层次:在映射文件的设置双方均使用association即可,用法相同

多对多映射的实现
1)实例:学生和课程、用户和角色
2)数据库层次:引入一个中间表将一个多对多转为两个一对多
3)MyBatis层次
方法1:在映射文件的设置双方均使用collection即可,不用引入中间类
方法2:引入中间类和中间类的映射文件,按照两个一对多处理
自关联映射
1)实例:Emp表中的员工和上级。一般是一对多关联
2)数据库层次:外键参考当前表的主键(比如mgr参考empno)
3)MyBatis层次:按照一对多处理,但是增加的属性都写到一个实体类中,增加的映射也都写到一个映射文件中

缓存

1. 一级缓存
一级存储是SqlSession上的缓存,默认开启,是一种内存型缓存,不要求实体类对象实现Serializable接口。(必须同一个SqlSession)
缓存中的数据使用键值对形式存储数据
namespace+sqlid+args+offset>>> hash值作为键,查询出的结果作为值
在这里插入图片描述

@Test
public void testFindDeptByDetpno()   {
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    Emp emp = mapper.findByEmpno(7521);
    System.out.println(emp);


    // 中间发生了增删改或者是调用了SqlSession调用了commit,会自动清空缓存
    sqlSession.commit();// 增删改的时候调用

    EmpMapper mapper2 = sqlSession.getMapper(EmpMapper.class);
    Emp emp2 = mapper2.findByEmpno(7521);
    System.out.println(emp2);

    System.out.println(emp==emp2);
    System.out.println(mapper==mapper2);

}

结果: emp == emp2 为true ,
mapper == mapper2 为false

2. 二级缓存
二级缓存是以namespace为标记的缓存,可以是由一个SqlSessionFactory创建的SqlSession之间共享缓存数据。默认并不开启。下面的代码中创建了两个SqlSession,执行相同的SQL语句,尝试让第二个SqlSession使用第一个SqlSession查询后缓存的数据。要求实体类必须实现序列化接口
在这里插入图片描述

开启:

1)全局开关:在mybatis.xml(核心)文件中的标签配置开启二级缓存

<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>

cacheEnabled的默认值就是true,所以这步的设置可以省略。

2)分开关:在要开启二级缓存的mapper文件中开启缓存:

<mapper namespace="com.xxx.mapper.EmployeeMapper">
    <cache/>
</mapper>

3)二级缓存未必完全使用内存,有可能占用硬盘存储,缓存中存储的JavaBean对象必须实现序列化接口,

public class Emp implements  Serializable {  }

经过设置后,查询结果如图所示。发现第一个SqlSession会首先去二级缓存中查找,如果不存在,就查询数据库,在commit()或者close()的时候将数据放入到二级缓存。第二个SqlSession执行相同SQL语句查询时就直接从二级缓存中获取了。
注意:
1)MyBatis的二级缓存的缓存介质有多种多样,而并不一定是在内存中,所以需要对JavaBean对象实现序列化接口。
2)二级缓存是以 namespace 为单位的,不同 namespace 下的操作互不影响
3)加入Cache元素后,会对相应命名空间所有的select元素查询结果进行缓存,而其中的insert、update、delete在操作是会清空整个namespace的缓存。
4)cache 有一些可选的属性 type, eviction, flushInterval, size, readOnly, blocking。
在这里插入图片描述
5)如果在加入Cache元素的前提下让个别select 元素不使用缓存,可以使用useCache属性,设置为false。useCache控制当前sql语句是否启用缓存 flushCache控制当前sql执行一次后是否刷新缓存

<select id="findByEmpno" resultType="emp" useCache="true" flushCache="false">

3. 三方缓存
分布式缓存框架:我们系统为了提高系统并发 和性能,一般对系统进行分布式部署(集群部署方式)不适用分布缓存, 缓存的数据在各个服务单独存储,不方便系统开发。所以要使用分布式缓存对缓存数据进行集中管理.ehcache,redis ,memcache缓存框架。
Ehcache:是一种广泛使用的开源java分布式缓存。主要面向通用缓存,javaEE 和 轻量级容器。它具有内存和磁盘存储功能。被用于大型复杂分布式web application的
这里的三方缓存是作为二级缓存使用的
导入依赖的jar文件

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.0.2</version>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.1</version>
</dependency>
<!--日志打印 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-nop</artifactId>
    <version>1.7.2</version>
</dependency>

去各自的sql映射文件里,开启二级缓存,并把缓存类型指定为EhcacheCache

 <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

在资源目录下放置一个缓存配置文件,文件名为: ehcache.xml 内容如下

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
         updateCheck="true" monitoring="autodetect"
         dynamicConfig="true">

    <diskStore path="D:\xxx\ehcache" />
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>


</ehcache>

        <!--  Cache配置
        ·           name:Cache的唯一标识
        ·           maxElementsInMemory:内存中最大缓存对象数。
        ·           maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大。
        ·           eternal:Element是否永久有效,一但设置了,timeout将不起作用。
        ·           overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中。
        ·           timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
        ·           timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大。
        ·           diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
        ·           diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
        ·           memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。     -->
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值