在mybatis3之前,需要學(xué)習(xí)和了解非常多標(biāo)簽,現(xiàn)在采用OGNL表達(dá)式語言,消除了許多其他標(biāo)簽
剩下
if
choose
trim
foreach
bind
if用法:
if通常用于WHERE語句中,判斷參數(shù)是否使用某個(gè)查詢條件,UPDATE語句中判斷是否更新某個(gè)字段,INSERT語句中判斷是否插入某個(gè)字段。
在WHERE語句中使用if
需求:
實(shí)現(xiàn)一個(gè)用戶管理高級查詢功能,根據(jù)輸入的條件去檢索用戶信息。當(dāng)只輸入用戶時(shí),需要根據(jù)用戶名進(jìn)行模糊查詢,當(dāng)只輸入郵箱時(shí),根據(jù)郵箱進(jìn)行完全匹配;當(dāng)同時(shí)輸入用戶名和郵箱時(shí),用這兩個(gè)條件去匹配用戶。
<select id="selectByUser" resultType="pers.congcong.myBatis2.pojos.SysUser">
SELECT id,
user_name userName,
user_password userPassward,
user_email userEmail,
user_info userInfo,
head_img headImg,
create_time createTime
FROM sys_user
WHERE 1=1
<if test="userName != null and userEmail != ''">
AND user_name LIKE concat('%', #{userName}, '%')
</if>
<if test="userEmail != null and userEmail != ''">
AND user_email = #{userEmail}
</if>
</select>
if標(biāo)簽有一個(gè)必填的屬性 test, test的屬性是一個(gè)符合OGNL要求的判斷表達(dá)式,表達(dá)式的結(jié)果為TRUE或FALSE,除此之外非0都為true,0為false。
@Test
public void testSelectByUser() {
SqlSession sqlSession = getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser sysUser = new SysUser();
sysUser.setUserName("ad");
List<SysUser> sysUserList = userMapper.selectByUser(sysUser);
Assert.assertTrue(sysUserList.size()>0);
// 根據(jù)郵箱查
sysUser.setUserEmail("test@mybatis.tk");
sysUser.setUserName(null);
sysUserList = userMapper.selectByUser(sysUser);
// 根據(jù)用戶和郵箱查
sysUser.setUserName("ad");
Assert.assertTrue(sysUserList.size()==0);
} finally {
sqlSession.close();
}
}
if 用法,加一個(gè)<if test ="property != ' ' and property == null">標(biāo)簽
中間加 and 條件。
if中符合條件才會有and條件。
在update中使用if
需求:
只更新變化的字段。需要注意,更新的時(shí)候不能將原來有值但沒發(fā)生變化的字段更新為空或者NULL。
通過IF就可以實(shí)現(xiàn)這種動態(tài)更新
示例:
<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>
測試:
@Test
public void testUpdateByIdSelective() {
SqlSession sqlSession = getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser sysUser = userMapper.selectById(1l);
sysUser.setUserName("cccc");
userMapper.updateByIdSelective(sysUser);
} finally {
sqlSession.rollback();
sqlSession.close();
}
}
在insert中使用if
應(yīng)用場景:
在數(shù)據(jù)表中插入?yún)?shù)是,如果參數(shù)值不為空,就傳入,如果傳入值為空,就使用數(shù)據(jù)庫中默認(rèn)的值,而不使用空值。
示例:
<insert id="insert2" 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= DATE}
)
</insert>
choose用法
可以實(shí)現(xiàn)if ...else...的邏輯
案例需求:
當(dāng)參數(shù)id有值的時(shí)候,優(yōu)先使用id查詢,當(dāng)id沒有值的時(shí)候,便去判斷用戶名是否有值,如果有值就用用戶名查詢,如果沒有值,就使SQL查詢無結(jié)果。
方案:
<select id="selectByIdOrUserName" resultType="pers.congcong.myBatis2.pojos.SysUser">
SELECT id,
user_name userName,
user_password userPassword,
user_email userEmail,
user_info userInfo,
head_img headImg,
create_time createTime
from sys_user
WHERE 1=1
<choose>
<when test="id != null">
AND id = #{id}
</when>
<when test="userName != null and userName != ''">
AND user_name = #{userName}
</when>
<otherwise>
and 1 = 2
</otherwise>
</choose>
</select>
測試代碼:
@Test
public void testselectByIdOrUserName() {
SqlSession sqlSession = getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
SysUser sysUser = userMapper.selectById(1l);
sysUser.setId(null);
SysUser sysUser1 = userMapper.selectByIdOrUserName(sysUser);
sysUser.setUserName(null);
sysUser1 = userMapper.selectByIdOrUserName(sysUser);
} finally {
sqlSession.close();
}
}
where/set/trim用法:
where標(biāo)簽的用法:如果標(biāo)簽包含的元素中有返回值,就插入一個(gè)where,如果where后面的字符串是以and和or開頭的,就將它們剔除。
where會自動剔除 and 或 or 開頭的 and 和 or
<select id="selectByUser" resultType="pers.congcong.myBatis2.pojos.SysUser">
SELECT id,
user_name userName,
user_password userPassward,
user_email userEmail,
user_info userInfo,
head_img headImg,
create_time createTime
FROM sys_user
<where>
<if test="userName != null and userEmail != ''">
AND user_name LIKE concat('%', #{userName}, '%')
</if>
<if test="userEmail != null and userEmail != ''">
AND user_email = #{userEmail}
</if>
</where>
</select>
set的用法:
如果標(biāo)簽包含元素中的返回值,就插入一個(gè)set,如果set后面中的元素是以逗號結(jié)尾的,就將這個(gè)逗號剔除。
但是如果set元素中沒有內(nèi)容,照樣會出現(xiàn)SQL錯(cuò)誤,所以,類似id = #{id}這樣必然存在的賦值任然需要保留。
例子:
<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},
</set>
WHERE id = #{id}
</update>
trim用法:
where和set都是通過trim實(shí)現(xiàn),并且底層都是通過TrimSqlNode實(shí)現(xiàn)的。
<trim prefix = "SET" suffixOverrides = ",">
...
</trim>
<trim prefix = "WHERE" prefixOverrides = "AND | OR">
...
</trim>
foreach用法
SQL語句中有時(shí)會使用IN關(guān)鍵字,例如 id in (1, 2, 3),可以使用$(ids)方式直接獲取值,但是不能放置SQL注入,避免SQL注入就需要使用#{}的方式,這是就要配合使用foreach標(biāo)簽來滿足需求。
foreach可以對數(shù)組、Map或?qū)崿F(xiàn)Iterable接口的對象進(jìn)行遍歷
foreach實(shí)現(xiàn)in集合
案例需求:
根據(jù)用戶ID集合查詢出所有符合條件的用戶
實(shí)現(xiàn):
<select id="selectByIdList" resultType="pers.congcong.myBatis2.pojos.SysUser">
SELECT id,
user_name userName,
user_password userPassword,
user_email userEmail,
user_info userInfo,
head_img headImg,
create_time createTime
FROM sys_user
WHERE id IN
<foreach collection="list" open="(" close=")" separator="," item="id" index="i">
#{id}
</foreach>
</select>
foreach包含以下屬性:
collection:必填,值為要迭代循環(huán)的屬性名。這個(gè)屬性值的情況很多。
item:變量名,值為從迭代對象中取出的每一個(gè)值。
index:索引的屬性名,在集合數(shù)組情況下值為當(dāng)前索引值,當(dāng)?shù)鷮ο笫荕ap類型是,這個(gè)值為KEY。
open、close、separator。
foreach實(shí)現(xiàn)批量插入:
如果數(shù)據(jù)庫支持批量插入,就可以通過foreach來實(shí)現(xiàn)。批量插入是SQL-92新增的特性,目前支持的數(shù)據(jù)庫有DB2、SQL Server8.2及其以上版本、Mysql、Sqlite3.7.11以上、H2。
批量插入語法如下:
INSERT INTO tablename (colum-a, [colum-b, ....])
VALUES('value-1a', ['value-1b', ...]),
('value-2a', ['value-2b', ...]),
....
例子:
<insert id="insertList" useGeneratedKeys="true" keyProperty="id">
INSERT INTO sys_user(
user_name, user_password, user_email, user_info, head_img, create_time
)
VALUES
<foreach collection="list" item="user" separator=",">
(
#{user.userName}, #{user.userPassword}, #{user.userEmail}, #{user.userInfo}, #{user.headImg, jdbcType= BLOB},
#{user.createTime, jdbcType= DATE}
)
</foreach>
</insert>
測試代碼:
@Test
public void testInsertList() {
SqlSession sqlSession = getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<SysUser> sysUserList = new ArrayList<SysUser>();
for (int i = 0; i < 2; i++) {
SysUser sysUser = new SysUser();
sysUser.setUserName("cc");
sysUser.setUserPassword("111111");
sysUser.setUserEmail("testck@qq.com");
sysUserList.add(sysUser);
}
int result = userMapper.insertList(sysUserList);
for (SysUser s :
sysUserList) {
System.out.println(s.getId());
}
Assert.assertEquals(2, result);
} finally {
//為了不影響其他測試,這里選擇回滾
sqlSession.rollback();
sqlSession.close();
}
}
這里使用了useGeneratedKeys 和 keyProperty 兩個(gè)屬性,可以實(shí)現(xiàn)批量插入后返回主鍵。
foreach實(shí)現(xiàn)動態(tài)update
這個(gè)主要介紹參數(shù)是Map時(shí),foreach怎么實(shí)現(xiàn)動態(tài)update。
bind標(biāo)簽,創(chuàng)建一個(gè)變量并將其綁定到上下文中。