动静SQL

if

  • 依据条件蕴含where子句的一部分

    <select id="findActiveBlogLike" resultType="Blog">  SELECT * FROM BLOG WHERE state = 'ACTIVE'  <where>      <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

    choose-when-otherwise

  • 不应用所有的条件,只是想从多个条件中抉择一个应用

    <select id="findActiveBlogLike" resultType="Blog">  SELECT * FROM BLOG WHERE state = 'ACTIVE'  <choose>      <when tset="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>

    where

  • where元素只会在子元素返回内容的状况下才会插入WHRER的子语句
  • 若子语句的结尾为AND或者OR,where元素会将这些去除

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

    trim

  • 能够通过自定义trim元素来定制where元素的性能

    • 比方和where元素等价的自定义trim元素.会移除所有prefixOverrides属性中指定的内容,并且插入prefix属性中指定的内容:

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

      prefixOverrides属性会疏忽通过管道符宰割的文本序列 ,不同的文本序列之间必须要有空格.

      • set元素等价的自定义trim元素. 笼罩了后缀值设置,并且自定义前缀值:
      <trim prefix="SET" suffixOverrides=",">    ...</trim>

      set

  • 用于动静更新语句的叫作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关键字,并会删掉额定的逗号,这些逗号是在应用条件语句给列赋值时引入的

    foreach

  • 对汇合进行遍历的时候应用foreach, 特地是在构建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容许指定一个汇合:

    • 申明能够在元素体内应用的汇合项item和索引index变量
    • 指定结尾open与结尾close的字符串以及汇合项迭代之间的分隔符separator
    • foreach不会谬误地增加多余的分隔符
  • 应用foreach时:

    • 能够将任何可迭代对象,比方List,Set,Map对象或者数组对象作为汇合参数传递给foreach
    • 当应用可迭代对象或者数组时:

      • index是以后迭代的序号
      • item的值是本次迭代获取到的元素
    • 当应用Map对象或者Map.Entry对象的汇合

      • index是键
      • item是值

        script

  • 要是想要在带注解的接口类中应用动静SQL语句,能够应用script元素

    @update({"<script>",          "update Author",              "<set>",                  "<if test='username != null'>username=#{username},</if>",                  "<if test='password != null'>password=#{password},</if>",                  "<if test='email != null'>email=#{email},</if>",                  "</set>",              "where id=#{id}",              "</script>"})    })void updateAuthorValues(Author author);

    bind

  • 能够应用bind元素在OGNL表达式以外创立一个变量,并绑定到上下文中

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

    多数据库反对

  • 如果配置了databaseIdProvider, 就能够在动静代码中应用名为 "_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中插入脚本语言

  • MyBatis 3.2版本开始反对插入脚本语言
  • 容许插入一种语言驱动,并基于这种语言来编写动静SQL查问语句
  • 通过实现LanguageDriver接口插入语言:

    public interface LanguageDriver {  ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);    SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);  SqlSource crateSqlSource(Configuration configuration, String script, Class<?> parameterType);}
  • 实现自定义语言驱动后,能够在mybatis-config.xml文件中设置为默认语言:

    <typeAliases>  <typeAliase type="com.oxford.MyLanguageDriver" alias="myLanguage" /></typeAliases><settings>  <setting name="defaultScriptingLanguage" value="myLanguage" /></settings>
  • 也能够应用lang属性为特定的语句指定语言:

    <select id="selectBlog" lang="myLanguage">  SELECT * FROM BLOG</select>
  • 或者在mapper接口上应用 @Lang注解:

    public interface Mapper {  @Lang(MyLanguageDriver.class)  @Select("SELECT * FROM BLOG")  List<Blog> selectBlog();}
  • MyBatis中的xml文件中的所有xml标签都由默认MyBatis语言提供,是由语言驱动org.apache.ibatis.scripting.xmltags.XmlLanguageDriver, 别名为xml. 提供的.

    Java API

  • MyBatis的执行办法在SqlSession类中

    语句执行办法

  • 这些办法被用来执行定义在SQL映射XML文件中的SELECT,INSERT,UPDATE和DELETE语句

    • 每一个办法都接管语句的ID以及参数对象
    • 参数能够是原始类型(反对主动装箱),包装类,JavaBean,POJO或者Map

      selectOne
      <T> T selectOne(String statement, Object parameter);
      selectList
      <E> List<E> selectList(String statement, Object parameter);
  • selectOne和selectList的不同点是:

    • selectOne必须返回一个对象或者null值, 如果返回值多于一个就会抛出异样
    • 如果不分明返回对象会有多少个,就应用selectList

      selectCursor
      <T> Cursor<T> selectCursor(String statement, Object parameter);
  • 游标Cursor与列表List返回的后果雷同,不同的是: 游标借助迭代器实现了数据的惰性加载

    try (Cursor<Entity> entities = session.selectCursor(statement, param)) {  for (Entity entity : entities) {      // 解决单个实体  }}   
    selectMap
    <K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey); 
  • selectMap会将返回对象的其中一个属性作为key值,将对象作为value值,从而将多个后果集转为Map类型值

    insert
    int insert(String statement, Object parameter);
    update
    int update(String statement, Object parameter);
    delete
    int delete(String statement, Obejct parameter);
  • 如果须要查看某个对象是否存在, 最好的方法就是查问一个count值,应用0或者1
  • 因为不是所有语句都须要参数,所以这些办法都具备一个不须要参数的重载模式
  • insert, updatedelete办法返回值示意受该语句影响的行数

    select高级版本

  • 容许限度返回行数的范畴
  • 提供自定义后果解决逻辑
  • 通常是在数据集十分宏大的情景下应用

    selectList
    <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
    selectCursor
    <T> List<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);
    selectMap
    <K, V> Map<K,V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
    select
    void select(String statement, Object parameter, ResultHandler<T> handler);
    select
    void select(String statement Object parameter, RowBounds rowBounds, ResultHandler<T> handler);
  • RowBounds参数:

    • 指定MyBatis略过指定数量的记录,并限度返回后果的数量
    • RowBounds类的offset和limit值只有在构造函数时能力传入,其余时候是不能批改的

      int offset = 100;int limit = 25;RowBounds rowBounds = new RowBounds(offset, limit);
  • ResultHandler参数:

    • 容许自定义每行后果的处理过程
    • 能够增加到List中,创立Map和Set. 甚至抛弃每个返回值,只保留计算后的统计后果
  • ResultHandler接口:

    package org.apache.ibatis.session;public interface ResultHandler<T> {  void handlerResult(ResultContext<? extends T> context);}
  • ResultContext参数:

    • 容许拜访后果对象和以后已被创立的对象数目
    • 提供一个返回值为Booleanstop办法,能够应用这个stop办法来进行MyBatis加载更多的后果
  • 应用ResultHandler要留神两条限度:

    • 应用带ResultHandler参数的办法时,收到的数据不会被缓存
    • 当应用高级的后果映射集resultMap,MyBatis很可能须要数行后果来结构一个对象.如果这时应用了ResultHandler, 可能会接管到关联association或者汇合collection中尚未被残缺填充的对象

      革除批量更新办法

  • ExecutorType设置为ExecutorType.BATCH时,能够应用flushStatements革除缓存在JDBC驱动类中的批量更新语句

    flushStatements
    List<BatchResult> flushStatements();

    事务管制办法

  • 管制事务作用域的办法有四个,如果曾经设置了主动提交或者应用了内部事务管理器, 就不须要应用这些办法
  • 如果正在应用Connection实例管制的JDBC事务管理器,就能够应用以下的四个办法:

    void commit();void commit(boolean force);void rollback();void rollback(boolean force);
  • 默认状况下 ,MyBatis不会主动提交事务,除非发现到调用了插入,更新或删除办法扭转了数据库
  • 如果没有应用这些办法提交批改,那么就能够在commitrollback办法参数传入true值来保障事务被失常提交

    • 留神: 在主动提交模式或者应用了内部事务管理器的状况下,设置force值对session有效
  • 大部分状况下,无需调用rollback(), 因为MyBatis会在没有调用commit() 时实现回滚操作
  • 然而,当要在一个可能屡次提交或回滚的session中具体管制事务,就要应用到回滚rollback操作