mybatis 的动态sql 和缓存
动态SQL
可以根据具体的参数条件,来对SQL语句进行动态拼接。
比如在以前的开发中,由于不确定查询参数是否存在,许多人会使用类似于where 1 = 1 来作为前缀,然后后面用AND 拼接要查询的参数,这样,就算要查询的参数为空,也能够正确执行查询,如果不加1 = 1,则如果查询参数为空,SQL语句就会变成SELECT * FROM student where ,SQL不合法。
mybatis里的动态标签主要有
if
<!-- 示例 -->
<select id="find" resultType="student" parameterType="student">
SELECT * FROM student WHERE age >= 18
<if test="name != null and name != ''">
AND name like '%${name}%'
</if>
</select>
当满足test条件时,才会将<if>标签内的SQL语句拼接上去
choose
<!-- choose 和 when , otherwise 是配套标签
类似于java中的switch,只会选中满足条件的一个
-->
<select id="findActiveBlogLike"
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 author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
trim
where
<where> 标签 只会在至少有一个子元素返回了SQL语句时,才会向SQL语句中添加WHERE,并且如果WHERE之后是以AND或OR开头,会自动将其删掉
<select id="findActiveBlogLike"
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 author_name like #{author.name}
</if>
</where>
</select>
<where>标签可以用<trim>标签代替
<trim prefix="WHERE" prefixOverrides="AND | OR">
...
</trim>
可以通过<trim>
标签更加灵活地对SQL进行定制
实际上在mybatis源码,也能看到trim与set,where标签的父子关系
foreach
用来做迭代拼接的,通常会与SQL语句中的IN查询条件结合使用,注意,到parameterType为List(链表)或者Array(数组),后面在引用时,参数名必须为list或者array。如在foreach标签中,collection属性则为需要迭代的集合,由于入参是个List,所以参数名必须为list
<select id="batchFind" resultType="student" parameterType="list">
SELECT * FROM student WHERE id in
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</select>
sql
可将重复的SQL片段提取出来,然后在需要的地方,使用<include>标签进行引用
<select id="findUser" parameterType="user" resultType="user">
SELECT * FROM user
<include refid="whereClause"/>
</select>
<sql id="whereClause">
<where>
<if test="user != null">
AND username like '%${user.name}%'
</if>
</where>
</sql>
bind
mybatis的动态SQL都是用OGNL表达式进行解析的,如果需要创建OGNL表达式以外的变量,可以用bind标签
<select id="selectBlogsLike" resultType="Blog"> <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" /> SELECT * FROM BLOG WHERE title LIKE #{pattern} </select>
缓存
一级缓存
默认开启,同一个SqlSesion级别共享的缓存,在一个SqlSession的生命周期内,执行2次相同的SQL查询,则第二次SQL查询会直接取缓存的数据,而不走数据库,当然,若第一次和第二次相同的SQL查询之间,执行了DML(INSERT/UPDATE/DELETE),则一级缓存会被清空,第二次查询相同SQL仍然会走数据库
一级缓存在下面情况会被清除
在同一个SqlSession下执行增删改操作时(不必提交),会清除一级缓存
SqlSession提交或关闭时(关闭时会自动提交),会清除一级缓存
对mapper.xml中的某个CRUD标签,设置属性flushCache=true,这样会导致该MappedStatement的一级缓存,二级缓存都失效(一个CRUD标签在mybatis中会被封装成一个MappedStatement)
在全局配置文件中设置 <setting name="localCacheScope" value="STATEMENT"/>,这样会使一级缓存失效,二级缓存不受影响
二级缓存
默认关闭,可通过全局配置文件中的<settings name="cacheEnabled" value="true"/>开启二级缓存总开关,然后在某个具体的mapper.xml中增加<cache />,即开启了该mapper.xml的二级缓存。二级缓存是mapper级别的缓存,粒度比一级缓存大,多个SqlSession可以共享同一个mapper的二级缓存。注意开启二级缓存后,SqlSession需要提交,查询的数据才会被刷新到二级缓存当中
关联查询
使用<resultMap>
标签以及<association>
和<collection>
子标签,进行关联查询,比较简单,不多说
延迟加载
延迟加载是结合关联查询进行应用的。也就是说,只在<association>
和<collection>
标签上起作用