Mybatis使用:Dynamic Sql
本节我们学习下Mybatis最强大的特性之一。
如果你使用过JDBC来拼接SQL语句,后者有其它简单ORM框架使用经验的话,你会明白根据根据条件拼接SQL是多么痛苦,少个括号,逗号,空格都是一种灾难。你需要仔细的测试你的SQL生成的各种结果来确保SQL拼接覆盖到了各种情况。这种情况特别影响心情,还有可能将隐患带到线上。如果出现这种情况的话,你听到bug的第一印象就是动态拼接SQL的问题,抓狂的感觉可想而知啦。
而使用Mybatis的Dynamic SQL能够让你处理、远离这种痛苦。
好吧,上面这段类似宣传的说明就是说明一件事:使用mybatis吧,Dynamic SQL特性能帮助你解决条件SQL拼接的问题。当然,前提是建立在你能熟悉、熟练Mybatis的Dynamic SQL特性的基础之上。
说了这么多,Dynamic SQL究竟能有多强大呢,我们通过例程来看下。
注意本文的Dynamic SQL我以前用过,现在回头看下特性差别不大,就不在单独写SQL验证,以官方的SQL教程为准,会加上一些自己的理解和使用场景,还有一些教程不太容易理解的地方。官方的Dynamic SQL地址见这里:http://www.mybatis.org/core/dynamic-sql.html
Dynamic SQL支持下面四种条件SQL:
if choose (when, otherwise) trim (where, set) foreach
我们分别来学习下这四种条件SQL的使用。
if
这个SQL是在Dynamic SQL里面使用最多,也是最为重要的一个,使用方法倒不难,看下if条件在where条件语句中的情况:
<select id="findActiveBlogWithTitleLike" parameterType="Blog" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <if test="title != null"> AND title like #{title} </if> </select>
这个SQL提供基本的查询功能state='active',另外提供一个可选的条件title:如果你传了title这个参数,就会添加上title这个条件。
如果想选择多个条件的话,if语句时可以叠加使用的:
<select id="findActiveBlogWithTitleAndCategoryLike" parameterType="Blog" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <if test="title != null"> AND title like #{title} </if> <if test="category != null"> AND category like #{category} </if> </select>
如果你添加的调试时Blog实体类中的对象的条件,如下面的author,判断author.name是否为空:
<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 author_name like #{author.name} </if> </select>
choose where other
在有些情况下,你不需要所有的条件,需要在多个条件中进行选择,如Java中的Switch或者if...else...判断:
<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 author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
根据test的结果添加条件,如果条件都不满足,则设定默认的条件,这个功能还是比较实用的,关键是思路清晰,易于理解。
trim, where, set
如果where后面的条件都是可选项怎么办?这三个参数就是解决这个问题的。这几个测试条件都比较特殊,需要仔细阅读体会。
<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 author_name like #{author.name} </if> </select>
比较容易理解,有三个判断条件,根据不同的判断条件进行不同的查询;但是很容易发现问题,入股偶这些条件都没有匹配时SQL会变成这样:
SELECT * FROM BLOG WHERE
这个明显是个Error1064语法错误,如果仅仅匹配第二个条件的话,SQL回事这样:
SELECT * FROM BLOG WHERE AND title like ‘someTitle’
这个也是个语法错误。对于where后面全部是条件判断的话,就不能用单纯的if语句了。
Mybatis的处理时将where也作为条件,这个是Dynamic SQL新添加的功能:
<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 author_name like #{author.name} </if> </where> </select>
where元素能根据被包含的判断,做出是否插入的判断;并且能够判断出AND和OR开头的内容。
在官方文档中还有一句话,如果上面的where没有按照期望工作的话,使用trim元素来自定义。这句话比较奇怪,莫非是官方不相信这个功能的准确性。
<select id="findActiveBlogLike" parameterType="Blog" resultType="Blog"> SELECT * FROM BLOG <trim prefix="WHERE" prefixOverrides="AND |OR "> <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> </trim> </select>
prefixOverrides属性会根据前缀覆盖内容,当然有前缀覆盖,也一定有后缀覆盖。
在使用动态更新时,使用类似的解决方案是set,set元素可以更新需要更新的列,而不需要全部更新;这个能让我们的SQL自行判断是否需要更新,如果你不设定值得花,SQL会忽略掉更新。这个会避免我们会将null值更新到数据库去,在很多情况下这个是不允许的。
<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>
更新数据时,只要设定需要更新的部分即可,不用全部重新设定。
相对应的trim元素可以写成这样:
<update id="updateAuthorIfNecessary" parameterType="domain.blog.Author"> update Author <trim prefix="SET",suffixOverrides=","> <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> </trim> where id=#{id} </update>
trim会覆盖掉后缀的逗号,使得SQL能够正常提交。
foreach
最后一个Dynamic 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=")"> #{item} </foreach> </select>
foreach操作非常强大;它能够根据你指定的集合,将其迭代应用在集合元素内。foreach能够指定开放和关闭的标记,并且能够指定迭代之间的分隔符,这个对于获得数据库指定多个状态的数据时很有效的。
bind
在前面我们看到过like的例子,在哪个例子中,你需要自行添加好匹配符之后,在传给SQL。如果你只想传入Bill,来获得author.name中包含有Bill的作家名称,你需要使用bind操作OGNL表达式:
<select id="selectBlogsLike" parameterType="Blog" resultType="Blog"> <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" /> SELECT * FROM BLOG WHERE title LIKE #{pattern} </select>
你只用传入Bill,就可以查询title中包含有Bill的title;而在前面中,你需要将title设定为'%Bill%',这个操作才是真正的like含义。
最后说下Dynamic SQL的插件式的脚本特性,这个需要最新mybatis 3.2的支持。
mybatis支持两种内置语言,xml和raw;上面讨论的都是xml,能够支持上面提到的所有元素。
但是raw语言的话就不会支持全部;当你使用raw格式来设定SQL时,Mybatis仅仅做参数替换后就将替换参数后的SQL提交给数据库。如你所见,对于Mybatis的Dynamic SQL特性来说,raw就是一种倒退。但是raw依然存在,因为它比xml格式要快。
对于raw的使用,实际上在开发者,如果你的SQL本身就比价简单,就不用经过一系列动态SQL解析,直接提交给数据库即可,下面我们看下例程:
<select id="selectBlog" lang="raw"> SELECT * FROM BLOG </select>
如果使用Annotation的话,可以这么使用:
public interface Mapper { @Lang(RawLanguageDriver.class) @Select("SELECT * FROM BLOG") List<Blog> selectBlog(); }
如果想创建自己的LanguageDriver的话,你需要实现LanguageDriver接口:
public interface LanguageDriver { public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql); public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType); public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType); }
如果你确认自己的SQL仅作参数替换,而不需要Dynamic特性的话,就可以设定自己的SQL为raw,提升性能。
Dynamic SQL的特性就这么多,如果理解深刻、使用熟练的话,那在工作中是如虎添翼,不用考虑SQL拼接了。这个对于开发者来说,能够更好的专注于业务逻辑的开发,提升工作效率。
本文就到这里。
相关推荐
Mybatis dynamic SQL mybatis之动态SQL
java运行依赖jar包
mybatis动态sql 1.什么是动态SQL? Mabits是一个Java持久化框架,它提供了动态SQL的功能。动态SQL是一种根据不同条件动态生成SQL语句的技术。在Mabits中,动态SQL通常是通过使用一组特殊的标签和代码块来实现的,...
Mybatis的自带分页方法只是逻辑分页,如果数据量很大,内存会溢出, 不知道为什么开源组织不在里面实现类似Hibernate的物理分页处理方法。 在不改动Mybatis源代码的情况下实现Mybatis支持物理分页
这是非常有用的一个功能,以往我们使用其他类型框架或者直接使用 JDBC 的时候,如果我们要达到同样的选择效果的时候,我们就需要拼 SQL 语句,这是极其麻烦的,比起来,上述的动态 SQL 就要简单多了。 2. choose ...
2. where标签查询时如果某些条件没带可能导致SQL拼装有问题,比如多出一个and 3. Trim标签 4. choose标签:分支选择,只会进入其中一个 5. set标签:封装修改条件 6. foreach标签:遍历集合 7. foreach标签:批量...
java运行依赖jar包
java运行依赖jar包
Mybatis mybatis공부(Spring启动和mybatis缓存,resultMap,dynamicSQL,事务)
MyBatis动态SQL这是什么? 该库是通用SQL生成器。 可以将其视为一种类型安全和可表达SQL DSL(域特定语言),并支持呈现针对MyBatis3和Spring的NamedParameterJDBCTemplate正确格式化SQL。 该库还包含Kotlin扩展,...
dynamic SQL是MyBatis的核心功能之一,它能够根据用户的输入参数生成不同的SQL语句,从而实现灵活的数据库操作。 在MyBatis中,dynamic SQL是通过OGNL表达式来实现的,OGNL(Object-Graph Navigation Language)是...
该项目旨在为开发者提供一个高效、便捷的Mybatis扩展解决方案,综合了Mybatis Plus、Dynamic SQL、JPA等框架特性和优点,利用Annotation Processor生成代码,支持代码自动生成、数据映射、动态SQL等功能,帮助开发者...
使用Mybatis Generator自动生成代码 可生成MyBatis3DynamicSql注解 也可xml MyBatis3类型
创建名为MyBaits的Dynamic Web Project,将mybatis和MySQL驱动包放入lib目录。 2. 数据库准备:创建名为"MyBaits"的数据库,建立一个名为"user"的表,包含id、userName、userAge和userAddress字段,并插入测试数据...
SpringBoot2.x+Mybatis+MySQL动态数据源Demo,可用于读写分离场景,但不包括分布式事务。
mybatis实战教程mybatis in action之九mybatis 代码生成工具的使用 mybatis SqlSessionDaoSupport的使用附代码下载 转自:http://www.yihaomen.com/article/java/302.htm (读者注:其实这个应该叫做很基础的入门...
MyBatis提供了多种方式来构建动态SQL语句,包括使用 `<sql>` 元素、 `<dynamic>` 元素、 `<isNotEmpty>` 元素等。在本实例中,我们使用 `<sql>` 元素来定义动态SQL片段,并使用 `<include>` 元素来包含这些片段。 ...
在上个资源myBatis001的基础上,加了缓存和动态sql的编写方式。。。。。。。。。。。。。。。。。。
7. **分页功能**:MyBatis 提供了分页查询的支持,可以通过编写 SQL 分页语句或使用 MyBatis 的插件来实现。 8. **动态SQL**:MyBatis 的动态 SQL 功能允许在映射文件中编写条件语句,根据实际情况动态生成 SQL,...
1.概述 spring boot项目整合mybatis,通过mybatis生成器插件进行扩展...使用mysql dynamicSql语法语句 要求jdk1.8及以上 3.方式一:模块安装方式 3.1 pom.xml配置 < groupId>org.mybatis.spring.boot < artif