1. 動态sql
動态sql是mybatis中的一個核心,什麼是動态sql?動态sql即對sql語句進行靈活操作,通過表達式進行判斷,對sql進行靈活拼接、組裝。就拿上一篇博文中對使用者的綜合查詢一例來說:
select * from user where user.sex = #{user.sex} and user.username like '%${user.username}%'
假如這個user是null咋整?或者user.sex或者user.username為null呢?是以更嚴謹的做法應該是在執行這個語句之前要先進行判斷才對,確定都不為空,那麼我再去查詢。這就涉及到了mybatis中的動态sql了。
在mybatis中,動态sql可以使用标簽來表示,這很類似于jstl表達式,我們可以将上面的sql語句改成動态sql,如下:
<select id="findUserList" parameterType="mybatis.po.UserQueryVo" resultType="mybatis.po.User">
select * from user <!-- where可以自動去掉條件中的第一個and -->
<where>
<if test="user!=null">
<if test="user.sex!=null and user.sex!=''">
and user.sex = #{user.sex} </if>
<if test="user.username!=null and user.username!=''">
and user.username like '%${user.username}%' </if>
</if>
</where>
</select>
上面的代碼很好了解,主要就是加了一些判斷,條件不為空,才進行查詢條件的拼接,讓mybatis動态的去執行。那麼在測試代碼中,我們可以故意的将user.sex不賦初值,就可以看到查詢的結果是不一樣的。
2. sql片段
那麼現在還有個問題,如果好幾個statement都需要這樣做,而且動态sql部分都一樣,這就會導緻一些代碼的重複,是以如果遇到這種情況,我們就應該抽取,動态sql也可以抽取,我們可以将動态的這部分sql抽取成sql片段,然後在具體的statement中引用進來即可。如下:
<sql id="query_user_where">
<if test="user!=null">
<if test="user.sex!=null and user.sex!=''">
and user.sex = #{user.sex} </if>
<if test="user.username!=null and user.username!=''">
and user.username like '%${user.username}%' </if>
</if>
</sql>
id是給該sql片段起個名字而已,内部就是上面的where動态部分,然後我們将上面原來的動态部分改成對這個sql片段的引用,如下:
<select id="findUserList" parameterType="mybatis.po.UserQueryVo" resultType="mybatis.po.User">
select * from user <where>
<!-- 引用sql片段的id,如果refid指定的id不在本mapper檔案中,需要在前面加上namespace -->
<include refid="query_user_where"></include>
<!-- 還可以引用其他sql片段 -->
</where>
</select>
3. foreach
還有個問題:如果我們要向sql傳遞數組或List該咋整呢?mybatis使用的是foreach解析。為了模拟這個場景,我們将上面的查詢改成多個id查詢,有兩種查詢方式:
SELECT * FROM USER WHERE id=1 OR id=12 OR id=17SELECT * FROM USER WHERE id IN(1,12,17)
首先有一點很明确,既然要使用多個id進行查詢,那麼多個id肯定要作為參數傳進來,是以存儲多個id的List需要放到UserQueryVo中作為一個屬性,這點很好了解,是以我們先在UserQueryVo中增加這個屬性:
//傳入多個id
private List<Integer> ids;
然後我們修改UserMapper.xml中的sql片段(還是寫在sql片段中),如下:
<sql id="query_user_where">
<if test="user!=null">
<if test="user.sex!=null and user.sex!=''">
and user.sex = #{user.sex} </if>
<if test="user.username!=null and user.username!=''">
and user.username like '%${user.username}%' </if>
</if>
<if test="ids!=null">
<!-- 使用右邊的sql拼接:AND (id=1 OR id=12 OR id=17) -->
<foreach collection="ids" item="user_id" open="AND (" close=")" separator="OR">
id=#{user_id}
</foreach>
</if>
</sql>
下面簡單介紹一下這個foreach中相關屬性的作用:
collection:指定輸入對象中的集合屬性,這裡就是這個ids。 item:表示每個周遊生成的對象,自己起個名兒,在foreach體中使用。 open:開始周遊時拼接的sql串。 close:結束周遊時拼接的sql串。 separator:周遊的兩個對象中需要拼接的sql串。
我們測試一下,然後看下控制台列印出來的sql就很容易了解了。測試程式:
@Testpublic void testFindUserList() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//建立UserMapper對象,mybatis自動生成mapper代理對象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//建立包裝對象,設定查詢條件
UserQueryVo userQueryVo = new UserQueryVo();
User user = new User();
//由于這裡使用動态sql,如果不設定某個值,條件不會拼接在sql中
user.setSex("男");
user.setUsername("倪升武");
//傳入多個id
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(12);
ids.add(17);
userQueryVo.setIds(ids);
userQueryVo.setUser(user);
//調用userMapper的方法
List<User> list = userMapper.findUserList(userQueryVo);
System.out.println(list);}
看下控制台列印出的sql:
select * from user WHERE user.sex = ? and user.username like '%倪升武%' AND ( id=? OR id=? OR id=? )
注意一個細節:在mybatis中,如果輸入的是Integer或者int類型的0,上面那個if判斷标簽傳回的是false,也就是說,即使非空非'',也不會拼接标簽體中的sql。
是以mybatis自動的将多個id拼接到了sql中。那麼另外一個sql的實作就不再贅述了,跟上面的一樣,唯一不同的就是sql片段部分,如下:
<!-- 使用右邊的sql拼接:AND id IN(1,12,17) -->
<foreach collection="ids" item="user_id" open="AND id IN(" close=")" separator=",">
#{user_id}</foreach>
本文作者: java樂園
本文來自雲栖社群合作夥伴“
JAVA樂園”,了解相關資訊可以關注“
”