MyBatis if 和多數據庫支持
1. 前言
動態 SQL 是 MyBatis 最標志性的特性之一。在其它框架中,你可能需要根據不同的條件來拼接 SQL,輾轉在符號與條件的判斷上,處理起來麻煩而且易錯,而 MyBatis 的動態 SQL 可以讓我們擺脫這種痛苦,簡單而又高效的書寫 SQL。
MyBatis 動態 SQL 由 OGNL 表達式和條件標簽兩部 分組成,我們將會分為多個小節進行介紹。
OGNL 表達式是動態 SQL 的基礎,如果你還不了解,請務必點擊學習一下。條件標簽部分我們將會在四個
小節中分別介紹,它們分別是MyBatis if 和多數據庫支持(本小節),MyBatis choose和bind小節,MyBatis where、set、trim小節和MyBatis foreach小節。
本小節,我們先來學習最基礎的條件標簽 if,以及如何使用 if 來讓 MyBatis 來支持多數據庫。
2. 定義
慕課解釋:
if
常用于 where 語句中,通過判斷參數來決定在 select 語句中是否使用某個查詢條件,或者在 update 語句中判斷是否更新一個字段,還可以在 insert 語句中決定是否插入一個滿足條件的值。
3. 實例
我們以一個實際的例子來看一下 if 是如何工作的。
<select id="selectUserByAgeAndScore" parameterType="com.imooc.mybatis.model.User" resultMap="userMap">
SELECT * FROM imooc_user
WHERE age = #{age}
<if test="score != null">
AND score = #{score}
</if>
</select>
在 if 標簽中,test 屬性是 OGNL 的判斷表達式。
selectUserByAgeAndScore 的作用是通過用戶年齡和積分來查詢用戶,當 score 值為 null 時,if 判斷不成立,此時生成的 SQL 語句為:
SELECT * FROM imooc_user WHERE age = ?
而當 if 成立時,生成的 SQL 語句為:
SELECT * FROM imooc_user WHERE age = ? AND score = ?
通過這樣條件判斷方式,MyBatis 能根據實際情況來動態生成 SQL 語句。
4. 實踐
4.1 例1、動態查詢用戶
請使用 MyBatis 完成對 imooc_user 表動態查詢用戶的功能, username為必須的查詢條件,年齡和積分若為 null 則不使用該字段進行過濾。
分析:
按照 MyBatis 的開發模式,先在 UserMapper.xml 文件中添加動態查詢用戶的 select 標簽,然后在 UserMapper.java 中增加上對應的方法。
步驟:
首先,在 UserMapper.xml 中添加 select 標簽,并在標簽中寫入 SQL,使用 if 來判斷屬性值是否為 null,若為 null,則不使用該字段進行查詢。如下:
<select id="selectUserByNameCondition" parameterType="com.imooc.mybatis.model.User"
resultType="com.imooc.mybatis.model.User">
SELECT * FROM imooc_user
WHERE username = #{username}
<if test="age != null">
AND age = #{age}
</if>
<if test="score != null">
AND score = #{score}
</if>
</select>
通過 if 對屬性的判斷,SQL 的過濾條件就會發生相應的變化。
然后在 UserMapper.java 中添加上對應的接口方法,方法接受 User對象作為參數。
package com.imooc.mybatis.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.imooc.mybatis.model.User;
@Mapper
public interface UserMapper {
User selectUserByNameCondition(User user);
}
結果:
通過如下代碼,我們運行 selectUserByNameCondition 這個方法。
UserMapper userMapper = session.getMapper(UserMapper.class);
User condition = new User();
condition.setUsername("pedro");
condition.setScore(200);
User pedro = userMapper.selectUserByNameCondition(condition);
System.out.println(pedro);
condition 對象 username 和 score 屬性均不為空,而 age 屬性為空,因此最后所執行的 SQL 為:
SELECT * FROM imooc_user WHERE username = ? AND score = ?
成功后,結果為:
User{id=2, username='pedro', age=24, score=200}
5. 多數據庫支持
MyBatis 可以根據不同的數據庫廠商執行不同的語句,這種多廠商的支持是基于配置文件中的 databaseId。
5.1 配置
首先在 MyBatis 的全局配置文件中添加如下配置:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<databaseIdProvider type="DB_VENDOR" />
</configuration>
在 configuration 中加入 databaseIdProvider 后,還需要在 databaseIdProvider 標簽中添加上需要使用到的數據庫名稱,如:SQL Server。每一個 property 屬性都代表了一個數據庫,name 表示數據庫廠商名稱,value 用來設置別名。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="MySQL" value="mysql"/>
<property name="PostgreSQL" value="postgre"/>
</databaseIdProvider>
</configuration>
5.2 使用
配置完畢后,我們就可以在 mapper xml 文件中,通過 if 來判斷當前的數據庫廠商,從而動態生成不同數據庫的 SQL。
例如,PostgreSQL 支持使用 ||
來拼接字符串,而 MySQL 需要使用 concat
函數來拼接字符串。
因此,如果在模糊查詢的時候,不同的數據庫廠商需要不同的 SQL 語句,通過 if 來判斷數據庫廠商來生成對于的 SQL 語句。
如下:
<select id="selectUserByLikeName" resultType="com.imooc.mybatis.model.User">
SELECT * FROM imooc_user
WHERE username LIKE
<if test="_databaseId == 'mysql'">
CONCAT('%',#{username},'%')
</if>
<if test="_databaseId == 'postgre'">
'%' || #{username} || '%'
</if>
</select>
注意,這里 _databaseId 參數是由 MyBatis 提供的內置參數,對應于 databaseIdProvider 中配置的數據庫名稱。
通過 databaseIdProvider 配置,即時數據庫廠商之間存在差異,但仍然可以通過動態 SQL 的形式來支持多數據庫。
6. 小結
- if 簡單且好用,是動態 SQL 中的最基礎的標簽,一看便會。
- 多數據庫支持的應用場景其實較少,但如果真的需要,也可通過 MyBatis 來方便的實現。