Github Mybatis深入学习之动态SQL .

动态SQL说的内容是根据输入条件决定的,所以需要对条件进行逻辑判断和处理。Mybatis提供了这样的标签来实现动态SQL的XML配置处理,实现了SQL语句和业务逻辑处理的兼容,而无需在代码中进行处理,完成了SQL的完美映射。

        原文地址:http://mybatis.github.io/mybatis-3/dynamic-sql.html

        MyBatis的最强大的功能之一就是动态SQL功能。如果您有任何经验与JDBC或任何类似的框架,你就明白条件地串联SQL字符串在一起,一定不要忘记空格或列的列表的末尾省略了一个逗号是多么痛苦。动态SQL可以彻底处理这种痛苦。当工作时绝不会使用动态SQL党,却肯定MyBatis提高的情况提供了强大的动态SQL语言,可以用在任何SQL映射语句。动态SQL元素应该与使用JSTL或任何类似的基于XML的文本处理器相似。 MyBatis的在以前的版本中,有很多元素的认识和了解。的MyBatis3大大提升,现在有不到一半的这些元素。 MyBatis的采用功能强大的基于OGNL表达式来消除其他元素:

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

    1、逻辑语句(if)

    最常见的事情在动态SQL有条件包括where子句中的一部分。例如:

    1. <SPAN style="FONT-SIZE: 12px"><select id="findActiveBlogWithTitleLike"  
    2.      parameterType="Blog" resultType="Blog">  
    3.   SELECT * FROM BLOG  
    4.   WHERE state = ‘ACTIVE’  
    5.   <if test="title != null">  
    6.     AND title like #{title}  
    7.   </if>  
    8. </select></SPAN>  
    <span style="font-size:12px;"><select id="findActiveBlogWithTitleLike"
         parameterType="Blog" resultType="Blog">
      SELECT * FROM BLOG
      WHERE state = ‘ACTIVE’
      <if test="title != null">
        AND title like #{title}
      </if>
    </select></span>
    这条语句会提供一个可选的文本查找功能。如果你没有传递title,那么所有激活的博客将被返回。但是,如果你传递一个标题,它会寻找这样的(敏锐的眼睛,是在这种情况下,你的参数值需要包括任何遮掩或通配符)标题。

    1. <SPAN style="FONT-SIZE: 12px"><select id="findActiveBlogLike"  
    2.      parameterType="Blog" resultType="Blog">  
    3.   SELECT * FROM BLOG WHERE state = ‘ACTIVE’  
    4.   <if test="title != null">  
    5.     AND title like #{title}  
    6.   </if>  
    7.   <if test="author != null and author.name != null">  
    8.     AND author_name like #{author.name}  
    9.   </if>  
    10. </select></SPAN>  
    <span style="font-size:12px;"><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></span>
    2、情形语句(choose, when, otherwise)
    有时候,我们不希望所有申请条件句,相反,我们要在众多选项中只能选择一个的情况下。类似Java中的switch语句,MyBatis的提供choose元素。让我们用上面的例子,但现在让我们只搜索标题。如果提供了,那么只能由作者提供;如果没有提供,我们只返回功能的博客(或许是战略性管理员选择列表,而不是返回大量没有意义的随机博客列表)。

    1. <SPAN style="FONT-SIZE: 12px"><select id="findActiveBlogLike"  
    2.      parameterType="Blog" resultType="Blog">  
    3.   SELECT * FROM BLOG WHERE state = ‘ACTIVE’  
    4.   <choose>  
    5.     <when test="title != null">  
    6.       AND title like #{title}  
    7.     </when>  
    8.     <when test="author != null and author.name != null">  
    9.       AND author_name like #{author.name}  
    10.     </when>  
    11.     <otherwise>  
    12.       AND featured = 1  
    13.     </otherwise>  
    14.   </choose>  
    15. </select></SPAN>  
    <span style="font-size:12px;"><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></span>
    3、条件语句(trim, where, set)

    前面的例子已经方便地演示了一个臭名昭著的动态SQL的挑战。考虑会发生什么,如果我们回到我们的“如果”的例子,但这次我们将“ACTIVE= 1”,以及一个动态的条件。

    1. <SPAN style="FONT-SIZE: 12px"><select id="findActiveBlogLike"  
    2.      parameterType="Blog" resultType="Blog">  
    3.   SELECT * FROM BLOG  
    4.   WHERE  
    5.   <if test="state != null">  
    6.     state = #{state}  
    7.   </if>  
    8.   <if test="title != null">  
    9.     AND title like #{title}  
    10.   </if>  
    11.   <if test="author != null and author.name != null">  
    12.     AND author_name like #{author.name}  
    13.   </if>  
    14. </select></SPAN>  
    <span style="font-size:12px;"><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></span>
    如果没有满足条件,会发生什么事,你会像这样结束SQL?
    1. <SPAN style="FONT-SIZE: 12px">SELECT * FROM BLOG  
    2. WHERE</SPAN>  
    <span style="font-size:12px;">SELECT * FROM BLOG
    WHERE</span>
    这会失败。如果只满足第二个条件是什么,你会像这样结束SQL?
    1. <SPAN style="FONT-SIZE: 12px">SELECT * FROM BLOG  
    2. WHERE  
    3. AND title like ‘someTitle’</SPAN>  
    <span style="font-size:12px;">SELECT * FROM BLOG
    WHERE
    AND title like ‘someTitle’</span>
    这也将失败。不会轻易用条件来解决这个问题,如果你曾经不得不写它,那么你可能永远都不想再次这样做。MyBatis有一个简单的答案,这将可能在90%的情况下工作。在那些情况下,你不会那么自定义它。有了一个简单的变化,一切正常:
    1. <SPAN style="FONT-SIZE: 12px"><select id="findActiveBlogLike"  
    2.      parameterType="Blog" resultType="Blog">  
    3.   SELECT * FROM BLOG  
    4.   <where>  
    5.     <if test="state != null">  
    6.          state = #{state}  
    7.     </if>  
    8.     <if test="title != null">  
    9.         AND title like #{title}  
    10.     </if>  
    11.     <if test="author != null and author.name != null">  
    12.         AND author_name like #{author.name}  
    13.     </if>  
    14.   </where>  
    15. </select></SPAN>  
    <span style="font-size:12px;"><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></span>
    其中元素知道只有插入“WHERE”如果有包含标签返回的任何内容。此外,如果该内容与“AND”或“OR”开头,它知道剥离其关闭。如果where元素的行为只要你喜欢的不完全相同,您可以自定义自己的装饰元素。例如,trim相当于where元素:
    1. <SPAN style="FONT-SIZE: 12px"><trim prefix="WHERE" prefixOverrides="AND |OR ">  
    2.   ...  
    3. </trim></SPAN>  
    <span style="font-size:12px;"><trim prefix="WHERE" prefixOverrides="AND |OR ">
      ...
    </trim></span>
    prefixOverrides属性需要一个管道分隔的列表的文本重写,其中空白有关。其结果是除去指定任何在prefixOverrides属性,和插入任何前缀属性。有一个类似的解决方案和动态更新语句称为set。 set元素可以用来动态地包含列更新,脱离其他的。例如:
    1. <SPAN style="FONT-SIZE: 12px"><update id="updateAuthorIfNecessary"  
    2.        parameterType="domain.blog.Author">  
    3.   update Author  
    4.     <set>  
    5.       <if test="username != null">username=#{username},</if>  
    6.       <if test="password != null">password=#{password},</if>  
    7.       <if test="email != null">email=#{email},</if>  
    8.       <if test="bio != null">bio=#{bio}</if>  
    9.     </set>  
    10.   where id=#{id}  
    11. </update></SPAN>  
    <span style="font-size:12px;"><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></span>
    在这里,set元素会动态前置SET关键字,还可以消除任何无关的逗号,应用条件后,可能落后的价值分配。如果你好奇相等的trim元素看起来会像什么,那就是:
    1. <SPAN style="FONT-SIZE: 12px"><trim prefix="SET" suffixOverrides=",">  
    2.   ...  
    3. </trim></SPAN>  
    <span style="font-size:12px;"><trim prefix="SET" suffixOverrides=",">
      ...
    </trim></span>
    请注意,在这种情况下,我们要覆盖后缀,同时我们还附加前缀。
    3、遍历(foreach)

    另一种常见的动态SQL的必要性是需要遍历一个集合,通常是构建在IN条件。例如:

    1. <SPAN style="FONT-SIZE: 12px"><select id="selectPostIn" resultType="domain.blog.Post">  
    2.   SELECT *  
    3.   FROM POST P  
    4.   WHERE ID in  
    5.   <foreach item="item" index="index" collection="list"  
    6.       open="(" separator="," close=")">  
    7.         #{item}  
    8.   </foreach>  
    9. </select></SPAN>  
    <span style="font-size:12px;"><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></span>
           foreach元素是非常强大的,它允许你指定一个集合,申报项目和索引变量,可用于身体内的元素。它还允许你打开和关闭指定的字符串,添加分隔符,在迭代之间放置。元素是很智能的,它不会偶然地附加多余的分隔符。
          注意:您可以传递一个List实例或者数组作为参数对象MyBatis的。当你这样做的时候,MyBatis将会自动包裹在Map和keyname。键入List实例名称“列表”和“数组”的名称将键入的数组实例。这包XML配置文件和XML映射文件的讨论。下一节将详细讨论Java API,所以,你可以得到最出你已经创建的映射。

    4、绑定(bind)

    bind元素可让你创建一个变量出OGNL表达式的值,并将其绑定到上下文。例如:

    1. <SPAN style="FONT-SIZE: 12px"><select id="selectBlogsLike" parameterType="Blog" resultType="Blog">  
    2.   <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />  
    3.   SELECT * FROM BLOG  
    4.   WHERE title LIKE #{pattern}  
    5. </select></SPAN>  
    <span style="font-size:12px;"><select id="selectBlogsLike" parameterType="Blog" resultType="Blog">
      <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
      SELECT * FROM BLOG
      WHERE title LIKE #{pattern}
    </select></span>
    5、多数据库厂商支持(Multi-db vendor support)
    如果一个databaseIdProvider是配置了“_databaseId”的变量是动态代码,所以你可以建立不同的语句,根据数据库供应商。看看下面的例子:

    1. <SPAN style="FONT-SIZE: 12px"><insert id="insert" parameterType="org.myapp.domain.User">  
    2.   <selectKey keyProperty="id" resultType="int" order="BEFORE">  
    3.     <if test="_databaseId == 'oracle'">  
    4.       select seq_users.nextval from dual  
    5.     </if>  
    6.     <if test="_databaseId == 'db2'">  
    7.       select nextval for seq_users from sysibm.sysdummy1"  
    8.     </if>  
    9.   </selectKey>  
    10.   insert into users values (#{id}, #{name})  
    11. </insert></SPAN>  
    <span style="font-size:12px;"><insert id="insert" parameterType="org.myapp.domain.User">
      <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></span>
    6、可插拔动态SQL的脚本语言(Pluggable Scripting Languages For Dynamic SQL)
    从3.2版的MyBatis支持可插拔的脚本语言,所以你可以插入一个语言驱动程序,并使用该语言编写动态SQL查询。有两个内置的语言:


    别名 驱动
    xml XmlLanguageDriver
    raw RawLanguageDriver
    XML语言是默认的。它是能够执行,我们在前面的章节中看到所有的动态标签。实际上是在原始语言的语言的情况下。当使用此设置MyBatis的执行参数替换语句传递到数据库的驱动程序。正如你可能猜到的,原始的语言是速度远远超过可扩展标记语言(XML)。您可以更改默认语言为您的项目通过配置MyBatis-config.xml文件:

    1. <SPAN style="FONT-SIZE: 12px"><settings>  
    2.   <setting name="defaultScriptingLanguage" value="raw"/>  
    3. </settings></SPAN>  
    <span style="font-size:12px;"><settings>
      <setting name="defaultScriptingLanguage" value="raw"/>
    </settings></span>
    您也可以指定你的语言要使用在一个特定的语句中加入lang属性,如下:
    1. <SPAN style="FONT-SIZE: 12px"><select id="selectBlog" lang="raw">  
    2.   SELECT * FROM BLOG  
    3. </select></SPAN>  
    <span style="font-size:12px;"><select id="selectBlog" lang="raw">
      SELECT * FROM BLOG
    </select></span>
    或者,如果你使用的是映射器,使用@Lang注解:
    1. <SPAN style="FONT-SIZE: 12px">public interface Mapper {  
    2.   @Lang(RawLanguageDriver.class)  
    3.   @Select("SELECT * FROM BLOG")  
    4.   List<Blog> selectBlog();  
    5. }</SPAN>  
    <span style="font-size:12px;">public interface Mapper {
      @Lang(RawLanguageDriver.class)
      @Select("SELECT * FROM BLOG")
      List<Blog> selectBlog();
    }</span>
    注:您可以使用Apache Velocity作为动态语言。有看看在MyBatis的速度的项目细节。您也可以实现你自己的语言驱动程序实现以下接口:
    1. <SPAN style="FONT-SIZE: 12px">public interface LanguageDriver {  
    2.   ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);  
    3.   SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);  
    4.   SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);  
    5. }</SPAN>  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MyBatis 是一个开源的持久层框架,可以方便地将 SQL 语句和 Java 对象进行映射。如果您想要学习 MyBatis 源码,可以按照以下步骤进行: 1. 了解 MyBatis 的架构和设计原理。可以阅读官方文档和相关书籍,例如《MyBatis 技术内幕》。 2. 下载 MyBatis 的源代码,并导入到 IDE 中。MyBatis 使用 Maven 进行构建,您可以使用 IDE 的 Maven 插件来下载依赖项。 3. 查看 MyBatis 的源代码结构。MyBatis 的主要代码在 `mybatis-3` 模块中,包括 `src/main/java` 和 `src/main/resources` 目录。其中,`src/main/java` 目录包含了 MyBatis 的核心代码,例如 `org.apache.ibatis.session.SqlSession` 类;`src/main/resources` 目录包含了 MyBatis 的配置文件和映射文件。 4. 阅读 MyBatis 的源代码。可以从 MyBatis 的入口处 `org.apache.ibatis.session.SqlSessionFactoryBuilder` 开始,深入了解 MyBatis 的初始化流程、SQL 语句的执行流程、映射文件的解析和缓存等。 5. 调试 MyBatis 的源代码。可以使用 IDE 的调试功能,对 MyBatis 进行单步调试,观察代码的执行流程,加深对 MyBatis 的理解。 6. 学习 MyBatis 的单元测试。MyBatis 的单元测试位于 `src/test/java` 目录中,可以通过单元测试来了解 MyBatis 的各个功能点的使用方法和测试用例。 7. 参与 MyBatis 的开发。如果您对 MyBatis 源码有深入的了解,并希望为 MyBatis 做出贡献,可以参与 MyBatis 的开发,贡献代码和文档,提交 issue 和 PR。MyBatis 的开发社区非常活跃,可以在官方网站和 GitHub 上找到相关信息。 希望这些步骤对您学习 MyBatis 源码有所帮助。 ### 回答2: MyBatis是一个开源的Java持久层框架,通过操作对象与数据库关系映射来提供数据持久化的功能。了解MyBatis源码是学习和使用该框架的重要一步。 首先,MyBatis的源码结构比较清晰,主要分为核心模块和附属模块。核心模块包括XML配置解析、SQL语句解析、参数处理、数据库连接管理等功能的实现,是实现MyBatis基本功能的核心部分。附属模块包括缓存、事务、插件等额外功能的实现,可以根据需要进行扩展和配置。 学习MyBatis源码可以从以下几个方面入手: 1. 配置文件解析:MyBatis通过XML配置文件来进行相关的配置,了解配置文件的解析过程可以帮助理解MyBatis的初始化过程和各项配置的作用。 2. SQL语句解析与执行:MyBatisSQL语句封装成MappedStatement对象进行管理,了解MappedStatement的生成过程,以及SQL语句的解析、参数处理和执行过程,可以深入了解MyBatisSQL执行原理。 3. 会话管理和事务处理:MyBatis采用SqlSessionFactory和SqlSession来管理数据库连接和事务,在MyBatis源码中可以学习到如何管理数据库连接池、事务的提交和回滚等核心功能的实现。 4. 缓存机制:MyBatis提供了一级缓存和二级缓存的功能,了解缓存的生成和更新过程,以及缓存的命中和失效原理,可以提高数据库查询性能。 总之,通过学习MyBatis源码,可以加深对该框架的理解,掌握其内部实现原理,有助于在使用时更加灵活和高效地进行开发。同时,也为以后解决一些特殊问题提供了更多的思路和方法。 ### 回答3: MyBatis是一个优秀的持久层框架,学习其源码有助于理解其底层原理和设计思想。 首先,可以从MyBatis的入口开始学习,即SqlSessionFactoryBuilder类。该类负责解析配置文件、创建Configuration对象,并通过Configuration对象创建SqlSessionFactory实例。 接下来,可以学习Configuration类,该类负责管理整个MyBatis的配置信息。其中包括了数据库连接信息、映射文件信息、缓存信息等。在该类内部,会调用XMLMapperBuilder类解析映射文件,在解析映射文件过程中,会创建MappedStatement对象,该对象表示一条SQL语句的映射信息。 学习MappedStatement对象可以了解MyBatisSQL语句解析过程。该对象包含了SQL语句的相关信息,包括参数映射关系、返回结果映射关系等。在执行SQL语句时,会使用ParameterHandler类处理参数,通过ResultSetHandler类处理查询结果。 同时,学习到Executor接口及其实现类,可以了解MyBatis的执行过程。Executor负责执行SQL语句,其中包括了写操作的update方法和读操作的query方法。在执行过程中,会通过StatementHandler类创建PreparedStatement对象,并通过ResultSetHandler类处理执行结果。 最后,还可以学习MyBatis的事务处理和缓存机制。Transaction接口及其实现类负责事务管理,通过JDBC的事务机制实现了事务的提交和回滚。而Cache接口及其实现类负责缓存查询结果,在查询时会先从缓存中查找结果。 总结来说,通过学习MyBatis的源码可以深入理解其底层原理和设计思想。从SqlSessionFactory的创建开始,到Configuration的配置解析、MappedStatement的创建,再到Executor的执行过程和Transaction的事务管理,以及Cache的缓存机制,逐步掌握MyBatis的各个组件和它们之间的交互关系。这对于我们使用MyBatis开发项目,解决问题和优化性能都具有积极的意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值