mybatis之动态SQL

来源:互联网 发布:单片机系统电路原理图 编辑:程序博客网 时间:2024/05/22 04:25

动态SQL
mybatis最强大的特点就是有动态SQL。如果你曾经使用过JDBC或者类似的框架,你可以明白把有条件的SQL字符串放在一起是多么痛苦,确定在列表的最后没有忘掉空格或者遗漏逗号。动态SQL可以完美的解决这一切。
然而使用动态SQL并不是永远很完美,mybatis在某种程度上使用强有力的动态SQL改善了那种环境,可以在任何映射的SQL语句中使用动态SQL。
动态SQL元素应该对于任何人来说都很熟悉,它采用了基于JSTL或者类似于XML的文本。在mybatis以前的版本中,这里有许多元素需要去了解和理解。mybatis3在这点改善了很多,现在这里只有大概不到一半的元素。mybatis使用了强大的OGNL表达式来排除其他的元素。
if
choose (when, otherwise)
trim (where, set)
foreach
if
动态SQL中最常见的是就是有条件的包含where子句的一部分,如下:

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

这个语句提供了一个功能性的可供选择的文本搜索类型。如果没有传title,所有激活的Blogs将会返回。但是如果你传递了一个title,它将会寻找与其相似的。
如果我们想通过title和author来进行选择会发生什么?首先,必须改变语句的名字来使其有意义。紧接着添加另一个条件

<select id="findActiveBlogLike"     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, when, otherwise
有时候我们不想所有的条件都被应用,相反我们想选择一些来进行应用。类似于JAVA中的switch语句。mybatis也提供了一个choose元素。
让我们使用上面的例子,但是现在让我们搜索仅仅被提供title的情况,接着搜索提供author的情况,如果两个都没有被提供,它就会返回有特征的blog(管理员或许在一个战略列表进行选择,而不是返回一个很大却没有意义的列表)。

<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, set
在前面的例子中已经挑战了动态SQL,考虑一下当我们返回我们的if例子时会发生什么,但是这次我们让active=1作为一个动态条件。

<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></select>

如果没有条件被发现会有什么结果?类似于下面的例子代码:

SELECT * FROM BLOGWHERE

将会失败。如果只有第二个条件出现,会发生什么?类似于下面这样结束你的SQL:

SELECT * FROM BLOGWHEREAND title like ‘someTitle’

这个也会失败。这个问题不是很容易被用条件来解决的。如果你曾经写过这样的,你将永远不会再这样做一次了。
mybatis有一个简单的答案可能在90%的例子中都会起作用。在这个例子中,你可以定制它让它起作用。

<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元素知道仅仅在包含标签有内容返回的地方插入。此外,如果内容以and或者or开头,它知道去除掉and或者or。
如果where子句并没有做出和你所想的那样的操作,你可以通过使用trim元素来定义,使它可以起作用。例如,trim等价于where元素,如下:

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

属性prefixOverrides 采用了管道文本的列表进行重写限制那些和空格有关的。结果是在属性prefixOverrides 任何具体的被移除。在属性prefix 中任何的插入。
对于动态SQL,这里也有一个相似的解决方案被叫做set。set元素可以被使用来动态包含列来更新,忽略其它。例如:

<update id="updateAuthorIfNecessary">  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>

注意:在这个例子中我们重写了一个suffix,然而我们仍然添加了一个prefix
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=")">        #{item}  </foreach></select>

foreach元素是很强大的,它允许你指定一个collection,声明item和index变量,可以在元素的body内部使用。它也允许你指定一个opening和closing字符串,并且添加一个separator 放在迭代之间。它不会偶然的增加额外的separator。
注意你可以传递Iterable变量(例如:list,set等),当然也有map或者数组对象来遍历当做collection的参数。当使用一个Iterable 或者数组,下标将会是当前迭代的数字,值将会是在迭代过程中取回的元素的值。当使用map,index将会是key对象,item将会是value对象。
这将讨论有关xml配置文件和xml映射文件.下个章节将会详细的讨论JAVA API,这样你就可以从你创建的映射中得到最多的
bind
bind元素可以让你从一个OGNL表达式创建一个变量,并且与上下文绑定,例如:

<select id="selectBlogsLike" resultType="Blog">  <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />  SELECT * FROM BLOG  WHERE title LIKE #{pattern}</select>

多个数据库供应商的支持
如果一个提供的数据库被配置了一个_databaseId变量,这个变量是一个可利用的动态代码,你可以依赖数据库供应商建立不同的语句,看一下下面这个例子:

<insert id="insert">  <selectKey keyProperty="id" resultType="int" order="BEFORE">    <if test="_databaseId == 'oracle'">      select seq_users.nextval from dual    </if>    <if test="_databaseId == 'db2'">      select nextval for seq_users from sysibm.sysdummy1"    </if>  </selectKey>  insert into users values (#{id}, #{name})</insert>

对于动态SQL来说Pluggable Scripting语言是从mybatis3.2开始的支持Pluggable Scripting语言,所以你可以添加一个语言驱动并且使用它来写你的动态SQL查询。
你可以通过实现下面的接口来添加一个语言:

public interface LanguageDriver {  ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);  SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);  SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);}

一旦你有自己的原因驱动你可以在mybatis-config.xml文件中设置为默认的语言。

<typeAliases>  <typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/></typeAliases><settings>  <setting name="defaultScriptingLanguage" value="myLanguage"/></settings>

而不是改变默认的,你可以通过添加lang元素为某个具体的语句来指定语言,如下所示:

<select id="selectBlog" lang="myLanguage">  SELECT * FROM BLOG</select>

或者,在这种情况下使用映射类,使用@Lang注解

public interface Mapper {  @Lang(MyLanguageDriver.class)  @Select("SELECT * FROM BLOG")  List<Blog> selectBlog();}

注意:你可以使用Apache Velocity作为你的动态语言,看一下MyBatis-Velocity可以得到更多详情。
All the xml tags you have seen in the previous sections are provided by the default MyBatis language that is provided by the driver org.apache.ibatis.scripting.xmltags.XmlLanguageDriver which is aliased as xml.

0 0
原创粉丝点击