動態SQL
if
<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物件的集合
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>
<select id="selectBlog" lang="myLanguage">
SELECT * FROM BLOG
</select>
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, update 和delete方法返回值表示受該語句影響的行數
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);
package org.apache.ibatis.session;
public interface ResultHandler<T> {
void handlerResult(ResultContext<? extends T> context);
}
- ResultContext引數:
- 允許訪問結果物件和當前已被建立的物件數目
- 提供一個返回值為Boolean的stop方法,可以使用這個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不會自動提交事務,除非發現到呼叫了插入,更新或刪除方法改變了資料庫
- 如果沒有使用這些方法提交修改,那麼就可以在commit和rollback方法引數傳入true值來保證事務被正常提交
- 注意: 在自動提交模式或者使用了外部事務管理器的情況下,設定force值對session無效
- 大部分情況下,無需呼叫rollback(), 因為MyBatis會在沒有呼叫commit() 時完成回滾操作
- 但是,當要在一個可能多次提交或回滾的session中詳細控制事務,就要使用到回滾rollback操作