天天看點

MyBatis中的動态sql1. 動态sql2. sql片段3. foreach

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樂園

”,了解相關資訊可以關注“