MyBatis从前世到今生一网打尽(全网最全,建议收藏)4️⃣

举报
XiaoLin_Java 发表于 2022/01/20 23:38:47 2022/01/20
【摘要】 六、MyBatis 动态 SQL 6.1、MyBatis 动态 SQL 简介​ 动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。这里的条件判断使用的表达式为 OGNL 表达式。常用的动态 SQL 标签有<if>、<where>、<choose/>、<foreach>等。​ MyBatis 的动态 SQL 语句,与 JSTL 中的语句非常相似。动...

六、MyBatis 动态 SQL

6.1、MyBatis 动态 SQL 简介

​ 动态 SQL,通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。这里的条件判

断使用的表达式为 OGNL 表达式。常用的动态 SQL 标签有<if>、<where>、<choose/>、<foreach>等。

​ MyBatis 的动态 SQL 语句,与 JSTL 中的语句非常相似。动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题。

  1. 动态 SQL 是 MyBatis 强大特性之一。极大的简化我们拼装 SQL 的操作
  2. 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似
  3. MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作
  4. OGNL( Object Graph Navigation Language )对象图导航语言,这是一种强大的表达式语言,通过它可以非常方便的来操作对象属性。 类似于我们的 EL,SpEL 等

注意:xml 中特殊符号如”,>,<等这些都需要使用转义字符

6.2、if和 where

if

If 用于完成简单的判断.

Where

Where 用于解决 SQL 语句中 where 关键字以及条件中第一个 and 或者 or 的问题

<select id="getEmpsByConditionIf" resultType="com.atguigu.mybatis.beans.Employee">
	select id , last_name ,email , gender
	from tbl_employee
		<where>
			<if test="id!=null">
				and id = #{id}
			</if>
			<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
				and last_name = #{lastName}
			</if>
			<if test="email!=null and email.trim()!=''">
				and email = #{email}
			</if>
			<if test="&quot;m&quot;.equals(gender) or &quot;f&quot;.equals(gender)">
				and gender = #{gender}
			</if>
		</where>
</select>

6.3、trim

Trim 可以在条件判断完的 SQL 语句前后 添加或者去掉指定的字符,常用方法如下:

​ prefix: 添加前缀
​ prefixOverrides: 去掉前缀
​ suffix: 添加后缀
​ suffixOverrides: 去掉后缀

<select id="getEmpsByConditionTrim" resultType="com.atguigu.mybatis.beans.Employee">
    select id , last_name ,email , gender from tbl_employee
	<trim prefix="where" suffixOverrides="and">
		<if test="id!=null">
			id = #{id} and
		</if>
		<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
			last_name = #{lastName} and
		</if>
		<if test="email!=null and email.trim()!=''">
			email = #{email} and
		</if>
		<if test="&quot;m&quot;.equals(gender) or &quot;f&quot;.equals(gender)">
			gender = #{gender}
		</if>
	</trim>
</select>

6.4、set

set 主要是用于解决修改操作中 SQL 语句中可能多出逗号的问题

<update id="updateEmpByConditionSet">
	update tbl_employee
	<set>
		<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
			last_name = #{lastName},
		</if>
		<if test="email!=null and email.trim()!=''">
			email = #{email} ,
		</if>
		<if test="&quot;m&quot;.equals(gender) or &quot;f&quot;.equals(gender)">
			gender = #{gender}
		</if>
	</set>
	where id =#{id}
</update>

6.5、choose(when、otherwise)

choose 主要是用于分支判断,类似于 java 中的 switch case,只会满足所有分支中的一个

<select id="getEmpsByConditionChoose" resultType="com.atguigu.mybatis.beans.Employee">
	select id ,last_name, email,gender from tbl_employee
	<where>
		<choose>
			<when test="id!=null">
				id = #{id}
			</when>
			<when test="lastName!=null">
				last_name = #{lastName}
			</when>
			<when test="email!=null">
				email = #{email}
			</when>
			<otherwise>
				gender = 'm'
			</otherwise>
		</choose>
	</where>
</select>

6.6、foreach

foreach 主要用户循环迭代

​ collection: 要迭代的集合
​ item: 当前从集合中迭代出的元素
​ open: 开始字符
​ close:结束字符
​ separator: 元素与元素之间的分隔符
​ index:
​ 迭代的是 List 集合: index 表示的当前元素的下标
​ 迭代的 Map 集合: index 表示的当前元素的 key

<select id="getEmpsByConditionForeach" resultType="com.atguigu.mybatis.beans.Employee">
		select id , last_name, email ,gender from tbl_employee where id in
	<foreach collection="ids" item="curr_id" open="(" close=")" separator="," >
		#{curr_id}
	</foreach>
</select>

6.7、sql

sql 标签是用于抽取可重用的 sql 片段,将相同的,使用频繁的 SQL 片段抽取出来,单
独定义,方便多次引用.

抽取sql

<sql id="selectSQL">
	select id , last_name, email ,gender from tbl_employee
</sql>

引用 SQL

<include refid="selectSQL"></include>

七、MyBatis 缓存机制

7.1、缓存的简介

  1. MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率
  2. MyBatis 系统中默认定义了两级缓存,一级缓存和二级缓存
  3. 默认情况下,只有一级缓存(SqlSession 级别的缓存,也称为本地缓存)开启。
  4. 二级缓存需要手动开启和配置,他是基于 namespace 级别的缓存
  5. 为了提高扩展性。MyBatis 定义了缓存接口 Cache。我们可以通过实现 Cache 接口来自定义二级缓存

7.2、 一级缓存的使用

一级缓存(local cache), 即本地缓存, 作用域默认为 sqlSession。当 Session flush 或close 后, 该 Session 中的所有 Cache 将被清空。本地缓存不能被关闭, 但可以调用 clearCache() 来清空本地缓存, 或者改变缓存的作用域.

7.2.1、一级缓存的工作机制

同一次会话期间只要查询过的数据都会保存在当前 SqlSession 的一个 Map 中
key: hashCode+查询的 SqlId+编写的 sql 查询语句+参数

7.2.2、一级缓存失效的几种情况

  1. 不同的 SqlSession 对应不同的一级缓存
  2. 同一个 SqlSession 但是查询条件不同
  3. 同一个 SqlSession 两次查询期间执行了任何一次增删改操作
  4. 同一个 SqlSession 两次查询期间手动清空了缓存

##7.3、二级缓存的使用

  1. 二级缓存(second level cache),全局作用域缓存, 二级缓存默认不开启,需要手动配置。

  2. MyBatis 提供二级缓存的接口以及实现,缓存实现要求 POJO 实现 Serializable 接口

  3. 二级缓存在 SqlSession 关闭或提交之后才会生效

二级缓存使用的步骤:

  1. 全局配置文件中开启二级缓存<setting name="cacheEnabled" value="true"/>
  2. 需要使用二级缓存的映射文件处使用 cache 配置缓存<cache />
  3. 注意:POJO 需要实现 Serializable 接口

二级缓存相关的属性

  1. eviction=“FIFO”:缓存回收策略:

  2. LRU – 最近最少使用的:移除最长时间不被使用的对象。

  3. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。

  4. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

  5. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。默认的是 LRU。

  6. flushInterval:刷新间隔,单位毫秒,默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

  7. size:引用数目,正整数,代表缓存最多可以存储多少个对象,太大容易导致内存溢出

  8. readOnly:只读,true/false

    true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被
    修改。这提供了很重要的性能优势。

    false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,
    因此默认是 false。

7.4、缓存的相关属性设置

属性 含义
全局 setting 的 cacheEnable 配置二级缓存的开关,一级缓存一直是打开的
select 标签的 useCache 属性 配置这个 select 是否使用二级缓存。一级缓存一直是使用的
sql 标签的 flushCache 属性 增删改默认 flushCache=true。sql 执行以后,会同时清空一级和二级缓存。查询默认 flushCache=false。
sqlSession.clearCache(): 只是用来清除一级缓存

7.5、整合第三方缓存

为了提高扩展性。MyBatis 定义了缓存接口 Cache。我们可以通过实现 Cache 接口来自定义二级缓存,EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider

整合 EhCache 缓存的步骤

  1. 导入 ehcache 包,以及整合包,日志包(maven也行)
    ehcache-core-2.6.8.jar、mybatis-ehcache-1.0.3.jar
    slf4j-api-1.6.1.jar、slf4j-log4j12-1.6.2.jar
  2. 编写 ehcache.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 磁盘保存路径 -->
<diskStore path="D:\atguigu\ehcache" />

<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
              overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>

<!--
属性说明:
l diskStore:指定数据在磁盘中的存储位置。
l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache
便会采用<defalutCache/>指定的的管理策略

以下属性是必须的:
l maxElementsInMemory - 在内存中缓存的element的最大数目
l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始
终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁
盘上

以下属性是可选的:
l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过
timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置
时间无穷大
l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活
时间无穷大
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认
是30MB.每个Cache都应该有自己的一个缓冲区.
l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是
false。
l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120
秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时
候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU
(最不常使用)和FIFO(先进先出)
-->
  1. 配置 cache 标签
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。