本篇博客主要講解如何使用if標簽生成動態的Sql,主要包含以下3個場景:
- 根據查詢條件實現動態查詢
- 根據參數值實現動態更新某些列
- 根據參數值實現動態插入某些列
1. 使用if標簽實現動態查詢
假設有這樣1個需求:根據用戶的輸入條件來查詢用戶列表,如果輸入了用戶名,就根據用戶名模糊查詢,如果輸入了郵箱,就根據郵箱精確查詢,如果同時輸入了用戶名和郵箱,就用這兩個條件去匹配用戶。
首先,我們在接口SysUserMapper中添加如下方法:
/**
* 根據動態條件查詢用戶信息
*
* @param sysUser
* @return
*/
List<SysUser> selectByUser(SysUser sysUser);
然后在對應的SysUserMapper.xml中添加如下代碼:
<select id="selectByUser" resultType="com.zwwhnly.mybatisaction.model.SysUser">
SELECT id,
user_name,
user_password,
user_email,
create_time
FROM sys_user
WHERE 1 = 1
<if test="userName != null and userName != ''">
AND user_name LIKE CONCAT('%',#{userName},'%')
</if>
<if test="userEmail != null and userEmail != ''">
AND user_email = #{userEmail}
</if>
</select>
代碼簡單講解:
1)if標簽的test屬性必填,該屬性值是一個符合OGNL要求的判斷表達式,一般只用true或false作為結果。
2)判斷條件property != null 或 property == null,適用於任何類型的字段,用於判斷屬性值是否為空。
3)判斷條件property != '' 或 property == '',僅適用於String類型的字段,用於判斷是否為空字符串。
4)當有多個判斷條件時,使用and或or進行連接,嵌套的判斷可以使用小括號分組,and相當於Java中的與(&&),or相關於Java中的或(||)。
所以上面代碼的意思就是先判斷字段是否為null,然后再判斷字段是否為空字符串。
最后,在SysUserMapperTest測試類中添加如下測試方法:
@Test
public void testSelectByUser() {
SqlSession sqlSession = getSqlSession();
try {
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
// 只按用戶名查詢
SysUser query = new SysUser();
query.setUserName("ad");
List<SysUser> sysUserList = sysUserMapper.selectByUser(query);
Assert.assertTrue(sysUserList.size() > 0);
// 只按郵箱查詢
query = new SysUser();
query.setUserEmail("test@mybatis.tk");
sysUserList = sysUserMapper.selectByUser(query);
Assert.assertTrue(sysUserList.size() > 0);
// 同時按用戶民和郵箱查詢
query = new SysUser();
query.setUserName("ad");
query.setUserEmail("test@mybatis.tk");
sysUserList = sysUserMapper.selectByUser(query);
// 由於沒有同時符合這兩個條件的用戶,因此查詢結果數為0
Assert.assertTrue(sysUserList.size() == 0);
} finally {
sqlSession.close();
}
}
運行測試代碼,測試通過,輸出日志如下:
DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE 1 = 1 AND user_name LIKE CONCAT('%',?,'%')
DEBUG [main] - ==> Parameters: ad(String)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time
TRACE [main] - <== Row: 1, admin, 123456, admin@mybatis.tk, 2019-06-27 18:21:07.0
DEBUG [main] - <== Total: 1
DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE 1 = 1 AND user_email = ?
DEBUG [main] - ==> Parameters: test@mybatis.tk(String)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time
TRACE [main] - <== Row: 1001, test, 123456, test@mybatis.tk, 2019-06-27 18:21:07.0
DEBUG [main] - <== Total: 1
DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE 1 = 1 AND user_name LIKE CONCAT('%',?,'%') AND user_email = ?
DEBUG [main] - ==> Parameters: ad(String), test@mybatis.tk(String)
DEBUG [main] - <== Total: 0
2. 使用if標簽實現動態更新
假設有這樣1個需求:更新用戶信息的時候不能將原來有值但沒有發生變化的字段更新為空或null,即只更新有值的字段。
首先,我們在接口SysUserMapper中添加如下方法:
/**
* 根據主鍵選擇性更新用戶信息
*
* @param sysUser
* @return
*/
int updateByIdSelective(SysUser sysUser);
然后在對應的SysUserMapper.xml中添加如下代碼:
<update id="updateByIdSelective">
UPDATE sys_user
SET
<if test="userName != null and userName != ''">
user_name = #{userName},
</if>
<if test="userPassword != null and userPassword != ''">
user_password = #{userPassword},
</if>
<if test="userEmail != null and userEmail != ''">
user_email = #{userEmail},
</if>
<if test="userInfo != null and userInfo != ''">
user_info = #{userInfo},
</if>
<if test="headImg != null">
head_img = #{headImg,jdbcType=BLOB},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
id = #{id}
WHERE id = #{id}
</update>
最后,在SysUserMapperTest測試類中添加如下測試方法:
@Test
public void testUpdateByIdSelective() {
SqlSession sqlSession = getSqlSession();
try {
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
SysUser sysUser = new SysUser();
// 更新id=1的用戶
sysUser.setId(1L);
// 修改郵箱
sysUser.setUserEmail("test@mybatis.tk");
int result = sysUserMapper.updateByIdSelective(sysUser);
Assert.assertEquals(1, result);
// 查詢id=1的用戶
sysUser = sysUserMapper.selectById(1L);
// 修改后的名字保持不變,但是郵箱變成了新的
Assert.assertEquals("admin", sysUser.getUserName());
Assert.assertEquals("test@mybatis.tk", sysUser.getUserEmail());
} finally {
sqlSession.close();
}
}
運行測試代碼,測試通過,輸出日志如下:
DEBUG [main] - ==> Preparing: UPDATE sys_user SET user_email = ?, id = ? WHERE id = ?
DEBUG [main] - ==> Parameters: test@mybatis.tk(String), 1(Long), 1(Long)
DEBUG [main] - <== Updates: 1
DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE id = ?
DEBUG [main] - ==> Parameters: 1(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time
TRACE [main] - <== Row: 1, admin, 123456, test@mybatis.tk, 2019-06-27 18:21:07.0
DEBUG [main] - <== Total: 1
3. 使用if標簽實現動態插入
假設有這樣1個需求:往數據庫表中插入數據的時候,如果某一列的參數值不為空,就使用傳入的值,如果傳入的參數值為空,就使用數據庫中的默認值(通常是空),而不使用傳入的空值。
為了更好的理解該示例,我們先給sys_user表的user_email字段設置默認值:test@mybatis.tk,Sql語句如下:
ALTER TABLE sys_user
MODIFY COLUMN user_email VARCHAR(50) NULL DEFAULT 'test@mybatis.tk'
COMMENT '郵箱'
AFTER user_password;
首先,我們在接口SysUserMapper中添加如下方法:
/**
* 根據傳入的參數值動態插入列
*
* @param sysUser
* @return
*/
int insertSelective(SysUser sysUser);
然后在對應的SysUserMapper.xml中添加如下代碼:
<insert id="insertSelective" useGeneratedKeys="true" keyProperty="id">
INSERT INTO sys_user(user_name, user_password,
<if test="userEmail != null and userEmail != ''">
user_email,
</if>
user_info, head_img, create_time)
VALUES (#{userName},#{userPassword},
<if test="userEmail != null and userEmail != ''">
#{userEmail},
</if>
#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP})
</insert>
最后,在SysUserMapperTest測試類中添加如下測試方法:
@Test
public void testInsertSelective() {
SqlSession sqlSession = getSqlSession();
try {
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
SysUser sysUser = new SysUser();
sysUser.setUserName("test-selective");
sysUser.setUserPassword("123456");
sysUser.setUserInfo("test info");
sysUser.setCreateTime(new Date());
sysUserMapper.insertSelective(sysUser);
// 獲取剛剛插入的數據
sysUser = sysUserMapper.selectById(sysUser.getId());
// 因為沒有指定userEmail,所以用的是數據庫的默認值
Assert.assertEquals("test@mybatis.tk", sysUser.getUserEmail());
} finally {
sqlSession.close();
}
}
運行測試代碼,測試通過,輸出日志如下:
DEBUG [main] - ==> Preparing: INSERT INTO sys_user(user_name, user_password, user_info, head_img, create_time) VALUES (?,?, ?,?,?)
DEBUG [main] - ==> Parameters: test-selective(String), 123456(String), test info(String), null, 2019-07-08 11:40:36.927(Timestamp)
DEBUG [main] - <== Updates: 1
DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, create_time FROM sys_user WHERE id = ?
DEBUG [main] - ==> Parameters: 1021(Long)
TRACE [main] - <== Columns: id, user_name, user_password, user_email, create_time
TRACE [main] - <== Row: 1021, test-selective, 123456, test@mybatis.tk, 2019-07-08 11:40:37.0
DEBUG [main] - <== Total: 1
4. 源碼及參考
源碼地址:https://github.com/zwwhnly/mybatis-action.git,歡迎下載。
劉增輝《MyBatis從入門到精通》