Mybatis特性值缓存和动态SQL

缓存

MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。MyBatis 3中的缓存实现的很多改进都已经实现了,使得它更加强大而且易于配置。

默认情况下是没有开启缓存的,除了局部的session缓存,可以增强变现而且处理循环依赖也是必须的。要开启二级缓存,你需要在你的SQL映射文件中添加一行:

<cache/> 

字面上看就是这样。这个简单语句的效果如下:

? 映射语句文件中的所有select语句将会被缓存。

? 映射语句文件中的所有insert,update和delete语句会刷新缓存。

? 缓存会使用Least Recently Used(LRU,最近最少使用的)算法来收回。

? 根据时间表(比如no Flush Interval,没有刷新间隔),缓存不会以任何时间顺序来刷新。

? 缓存会存储列表集合或对象(无论查询方法返回什么)的1024个引用。

? 缓存会被视为是read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

所有的这些属性都可以通过缓存元素的属性来修改。比如:

<cache
    eviction="FIFO"
    flushInterval="60000"
    size="512"
    readOnly="true"/> 

这个更高级的配置创建了一个FIFO缓存,并每隔60秒刷新,存数结果对象或列表的512个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。

可用的收回策略有:

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

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

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

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

默认的是LRU。

flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。

readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

使用自定义缓存

除了这些自定义缓存的方式,你也可以通过实现你自己的缓存或为其他第三方缓存方案创建适配器来完全覆盖缓存行为。

<cache type=”com.domain.something.MyCustomCache”/> 

这个示例展示了如何使用一个自定义的缓存实现。type属性指定的类必须实现org.mybatis.cache.Cache接口。这个接口是MyBatis框架中很多复杂的接口之一,但是简单给定它做什么就行。

public interface Cache {
    String getId();
    int getSize();
    void putObject(Object key, Object value);
    Object getObject(Object key);
    boolean hasKey(Object key);
    Object removeObject(Object key);
    void clear();
    ReadWriteLock getReadWriteLock();
} 

要配置你的缓存,简单和公有的JavaBeans属性来配置你的缓存实现,而且是通过cache元素来传递属性,比如,下面代码会在你的缓存实现中调用一个称为“setCacheFile(String file)”的方法:

<cache type=”com.domain.something.MyCustomCache”>
    <property name=”cacheFile” value=”/tmp/my-custom-cache.tmp”/>
</cache> 

你可以使用所有简单类型作为JavaBeans的属性,MyBatis会进行转换。

记得缓存配置和缓存实例是绑定在SQL映射文件的命名空间是很重要的。因此,所有在相同命名空间的语句正如绑定的缓存一样。语句可以修改和缓存交互的方式,或在语句的语句的基础上使用两种简单的属性来完全排除它们。默认情况下,语句可以这样来配置:

<select ... flushCache=”false” useCache=”true”/>
<insert ... flushCache=”true”/>
<update ... flushCache=”true”/>
<delete ... flushCache=”true”/> 

因为那些是默认的,你明显不能明确地以这种方式来配置一条语句。相反,如果你想改变默认的行为,只能设置flushCache和useCache属性。比如,在一些情况下你也许想排除从缓存中查询特定语句结果,或者你也许想要一个查询语句来刷新缓存。相似地,你也许有一些更新语句依靠执行而不需要刷新缓存。

动态SQL

MyBatis的一个强大的特性之一通常是它的动态SQL能力。如果你有使用JDBC或其他

相似框架的经验,你就明白条件地串联SQL字符串在一起是多么的痛苦,确保不能忘了空格或在列表的最后省略逗号。动态SQL可以彻底处理这种痛苦。

通常使用动态SQL不可能是独立的一部分,MyBatis当然使用一种强大的动态SQL语言来改进这种情形,这种语言可以被用在任意映射的SQL语句中。

动态SQL元素和使用JSTL或其他相似的基于XML的文本处理器相似。在MyBatis之前的版本中,有很多的元素需要来了解。MyBatis 3大大提升了它们,现在用不到原先一半的元素就能工作了。MyBatis采用功能强大的基于OGNL的表达式来消除其他元素。

? if
? choose(when,otherwise)
? trim(where,set)
? foreach 

If

在动态SQL中所做的最通用的事情是包含部分where字句的条件。比如:

<select id=”findActiveBlogWithTitleLike” parameterType=”Blog” resultType=”Blog”>
    SELECT * FROM BLOG
    WHERE state = "ACTIVE?
    <if test="title != null">
        AND title like #{title}
    </if>
</select> 

这条语句会提供一个可选的文本查找功能。如果你没有传递title,那么所有激活的博客都会被返回。但是如果你传递了title,那么就会查找相近的title(对于敏锐的检索,这中情况下你的参数值需要包含任意的遮掩或通配符)的博客。

假若我们想可选地搜索title和author呢?首先,要改变语句的名称让它有意义。然后简单加入另外的一个条件。

<select id=”findActiveBlogLike” parameterType=”Blog” resultType=”Blog”>
    SELECT * FROM BLOG WHERE state = ?ACTIVE?
    <if test=”title != null”>
        AND title like #{title}
    </if>
    <if test=”author != null and author.name != null”>
        AND title like #{author.name}
    </if>
</select> 

choose, when, otherwise

有时我们不想应用所有的条件,相反我们想选择很多情况下的一种。和Java中的switch语句相似,MyBatis提供choose元素。

我们使用上面的示例,但是现在我们来搜索当title提供时仅有title条件,当author提供时仅有author条件。如果二者都没提供,只返回featured blogs(也许是由管理员策略地选择的结果列表,而不是返回大量没有意义的随机博客结果列表)。

<select id=”findActiveBlogLike”
    parameterType=”Blog” resultType=”Blog”>
    SELECT * FROM BLOG WHERE state = ?ACTIVE?
    <choose>
        <when test=”title != null”>
            AND title like #{title}
        </when>
        <when test=”author != null and author.name != null”>
            AND title like #{author.name}
        </when>
        <otherwise>
            AND featured = 1
        </otherwise>
    </choose>
</select> 

trim, where, set

前面的例子已经方便地处理了一个臭名昭著的动态SQL问题。要考虑我们回到“if”示例后会发生什么,但是这次我们将“ACTIVE = 1”也设置成动态的条件。

<select id=”findActiveBlogLike” parameterType=”Blog” resultType=”Blog”>
    SELECT * FROM BLOG
    WHERE
    <if test=”state != null”>
        state = #{state}
    </if>
    <if test=”title != null”>
        AND title like #{title}
    </if>
    <if test=”author != null and author.name != null”>
        AND title like #{author.name}
    </if>
</select> 

如果这些条件都没有匹配上将会发生什么?这条SQL结束时就会成这样:

SELECT * FROM BLOG
WHERE 

这会导致查询失败。如果仅仅第二个条件匹配是什么样的?这条SQL结束时就会是这样:

SELECT * FROM BLOG
WHERE
AND title like ?someTitle? 

这个查询也会失败。这个问题不能简单的用条件来解决,如果你从来没有这样写过,那么你以后也不会这样来写。

MyBatis有一个简单的处理,这在90%的情况下都会有用。而在不能使用的地方,你可以自定义处理方式。加上一个简单的改变,所有事情都会顺利进行:

<select id=”findActiveBlogLike” parameterType=”Blog” resultType=”Blog”>
    SELECT * FROM BLOG
    <where>
        <if test=”state != null”>
            state = #{state}
        </if>
        <if test=”title != null”>
            AND title like #{title}
        </if>
        <if test=”author != null and author.name != null”>
            AND title like #{author.name}
        </if>
    </where>
</select> 

where元素知道如果由被包含的标记返回任意内容,就仅仅插入“WHERE”。而且,如果以“AND”或“OR”开头的内容,那么就会跳过WHERE不插入。

如果where元素没有做出你想要的,你可以使用trim元素来自定义。比如,和where元素相等的trim元素是:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
…
</trim> 

overrides属性采用管道文本分隔符来覆盖,这里的空白也是重要的。它的结果就是移除在overrides属性中指定的内容,插入在with属性中的内容。

和动态更新语句相似的解决方案是set。set元素可以被用于动态包含更新的列,而不包含不需更新的。比如:

<update id="updateAuthorIfNecessary" parameterType="domain.blog.Author">
    update Author
    <set>
        <if test="username != null">username=#{username},</if>
        <if test="password != null">password=#{password},</if>
        <if test="email != null">email=#{email},</if>
        <if test="bio != null">bio=#{bio}</if>
    </set>
    where id=#{id}
</update> 

这里,set元素会动态前置SET关键字,而且也会消除任意无关的逗号,那也许在应用条件之后来跟踪定义的值。

如果你对和这相等的trim元素好奇,它看起来就是这样的:

<trim prefix="SET" suffixOverrides=",">
…
</trim> 

注意这种情况下我们覆盖一个后缀,而同时也附加前缀。

foreach

另外一个动态SQL通用的必要操作是迭代一个集合,通常是构建在IN条件中的。比如:

<select id="selectPostIn" resultType="domain.blog.Post">
    SELECT *
    FROM POST P
    WHERE ID in
    <foreach item="item" index="index" collection="list"
        open="(" separator="," close=")">
    </foreach>
</select> 

foreach元素是非常强大的,它允许你指定一个集合,声明集合项和索引变量,它们可以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。

注意:你可以传递一个List实例或者数组作为参数对象传给MyBatis。当你这么做的时候,MyBatis会自动将它包装在一个Map中,用名称在作为键。List实例将会以“list”作为键,而数组实例将会以“array”作为键。

这个部分是对关于XML配置文件和XML映射文件的而讨论的。下一部分将详细讨论Java API,所以你可以得到你已经创建的最有效的映射。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-29 09:44:42

Mybatis特性值缓存和动态SQL的相关文章

MyBatis学习总结_11_MyBatis动态Sql语句

MyBatis中对数据库的操作,有时要带一些条件,因此动态SQL语句非常有必要,下面就主要来讲讲几个常用的动态SQL语句的语法 MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) trim where set foreach 1.if 对属性进行判断,如果不为空则执行判断条件 [html] view plaincopy <select id="selectByCriteria" parameterType="com.mu

MyBatis学习总结(六)——动态SQL

MyBatis的动态SQL是基于OGNL表达式的,它可以帮助我们方便的在SQL语句中实现某些逻辑. MyBatis中用于实现动态SQL的元素主要有: if choose(when,otherwise) foreach where set trim 下面我们主要说 where set trim 这三个标签 1,where标签 <!-- 查询学生list,like姓名,=性别 --> <select id="getStudentListWhere" parameterTy

mybatis入门篇3 ---- 动态sql,缓存,以及分页jar包的使用

首先我们来看一下动态sql,动态sql就是传递的参数不确定的时候,使用if,where,select,choose,set等标签,先来看一下 lib,rescources,以及utils里面文件不变,直接来看使用 直接看if跟where,if使用比较简单,就是if会有一个条件判断,如果条件满足,就会把if里面的sql语句块加入slq语句,where就是帮助我们加载一个where条件判断,并且会把拼接语句中的第一个and删除掉,接下来看一下例子 看一下UserMapper public inter

Mybatis映射原理,动态SQL,log4j

1.理清mybatis中的#和$之间的区别? #{ }:表示一个预处理参数,参数类型不定,是根据传入的参数类型来设定的. 类似于JDBC中的? 特例使用,模糊查询:(针对oracle): and username like concat(concat('%',#{username}),'%') 采取的$的方式传入参数,所有采取$的方式传入的参数都只是字符串(无论传入的是什么,都会当成字符串处理),潜在的危险就是SQL注入的问题. and username like '%${value}%' 注意

MyBatis 源码分析——动态SQL语句

有几年开发经验的程序员应该都有暗骂过原生的SQL语句吧.因为他们不能一句就搞定一个业务,往往还要通过代码来拼接相关的SQL语句.相信大家会理解SQL里面的永真(1=1),永假(1=2)的意义吧.所以mybatis动态SQL功能在笔者看来是最引吸人的.为了更好的区别XML映射文件上的SQL语句.mybatis把SQL语句分为四类.那么这个笔者已经在前面的章节里面讲过了.但是我们在开发过程中常常用到的也就俩种:静态和动态. 关于静态和动态的定义,笔者是这样子理解的--静态SQL语句显示就是里面没有相

(转)Mybatis高级映射、动态SQL及获得自增主键

原文:http://www.cnblogs.com/edwinchen/p/4105278.html?utm_source=tuicool&utm_medium=referral 一.动态SQL 相信大家在用mybatis操作数据库时时都会碰到一个问题,假如现在我们有一个关于作者的list authorList,需要根据authorList里已有的作者信息在数据库中查询相应作者的博客信息.那么最容易想到的做法就是遍历authorList,获取相应的信息查询数据库. for(int i=0;I &l

Mybatis高级映射、动态SQL及获得自增主键

一.动态SQL 相信大家在用mybatis操作数据库时时都会碰到一个问题,假如现在我们有一个关于作者的list authorList,需要根据authorList里已有的作者信息在数据库中查询相应作者的博客信息.那么最容易想到的做法就是遍历authorList,获取相应的信息查询数据库. for(int i=0;I < authorList.size();i++) { …… //查询数据库代码 //select * from blog where author=#{author,jdbcType

MyBatis 之 使用五 动态SQL

MyBatis 提供使用 ognl 表达式动态生成 SQL的功能. 1. if 2. where where 可以自动处理掉第一个拼接条件里的 and <!-- 动态 sql 查询用户信息 -->   <select id="findUserByDynamicSql" parameterType="user" resultType="user">    select * from users    <!-- wher

【MyBatis学习07】动态sql

1. 动态sql 动态sql是mybatis中的一个核心,什么是动态sql?动态sql即对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接.组装.就拿上一篇博文中对用户的综合查询一例来说: select * from user where user.sex = #{user.sex} and user.username like '%${user.username}%' 假如这个user是null咋整?或者user.sex或者user.username为null呢?所以更严谨的做