mybatis 動態sql與OGNL表達式

 
(瞭解)OGNL( Object Graph Navigation Language )對象圖導航語言,這是一種強大的
表達式語言,通過它可以非常方便的來操作對象屬性。 類似於我們的EL,SpEL等
訪問對象屬性: person.name
調用方法: person.getName()
調用靜態屬性/方法: @java.lang.Math@PI
@java.util.UUID@randomUUID()
調用構造方法: new com.atguigu.bean.Person(‘admin’).name
運算符: +,-*,/,%
邏輯運算符: in,not in,>,>=,<,<=,==,!=
注意:xml中特殊符號如”,>,<等這些都需要使用轉義字符
類型 僞屬性 僞屬性對應的 Java 方法
ListSetMap sizeisEmpty List/Set/Map.size(),List/Set/Map.isEmpty()
ListSet iterator List.iterator()Set.iterator()
Map keysvalues Map.keySet()Map.values()
Iterator nexthasNext Iterator.next()Iterator.hasNext()
 

MyBatis 採用功能強大的基於 OGNL 的表達式來簡化操作。

if
choose (when, otherwise)
trim (where, set)
– foreach(難點)
– sql片段
 

if測試

if舉例:

	<select id="getEmpsByConditionIf" resultType="com.bean.Employee">
		select * from tbl_employee
		<where>
		 	<if test="id!=null">
		 		id=#{id}
		 	</if>
		 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
		 		and last_name like #{lastName}
		 	</if>
		 	<if test="email!=null and email.trim()!=&quot;&quot;">
		 		and email=#{email}
		 	</if> 
		 	<!-- ognl會進行字符串與數字的轉換判斷  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 	 	and gender=#{gender}
		 	</if>			
		</where>
	</select>

choose (when, otherwise)測試

chose舉例:

	 <!-- public List<Employee> getEmpsByConditionChoose(Employee employee); -->
	 <select id="getEmpsByConditionChoose" resultType="com.bean.Employee">
	 	select * from tbl_employee 
	 	<where>
	 		<!-- 如果帶了id就用id查,如果帶了lastName就用lastName查;只會進入其中一個 -->
	 		<choose>
	 			<when test="id!=null">
	 				id=#{id}
	 			</when>
	 			<when test="lastName!=null">
	 				last_name like #{lastName}
	 			</when>
	 			<when test="email!=null">
	 				email = #{email}
	 			</when>
	 			<otherwise>
	 				gender = 0
	 			</otherwise>
	 		</choose>
	 	</where>
	 </select>

trim (where, set)測試

trim用來自定義字符串的截取規則 ,trim標籤體中是整個字符串拼串後的結果。 

trim標籤屬性:
prefix=" "
前綴:prefix給拼串後的整個字符串加一個前綴 
prefixOverrides=" "
前綴覆蓋: 去掉整個字符串前面多餘的字符
suffix=" "

後綴:suffix給拼串後的整個字符串加一個後綴 
suffixOverrides=" "

後綴覆蓋:去掉整個字符串後面多餘的字符

trim舉例:

	 <!--public List<Employee> getEmpsByConditionTrim(Employee employee);  -->
	 <select id="getEmpsByConditionTrim" resultType="com.bean.Employee">
	 	select * from tbl_employee
	 	<!-- 自定義字符串的截取規則 -->
	 	<trim prefix="where" suffixOverrides="and"> <!-- 將最後的and去掉 -->
	 		<if test="id!=null">
		 		id=#{id} and
		 	</if>
		 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
		 		last_name like #{lastName} and
		 	</if>
		 	<if test="email!=null and email.trim()!=&quot;&quot;">
		 		email=#{email} and
		 	</if> 
		 	<!-- ognl會進行字符串與數字的轉換判斷  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 	 	gender=#{gender}
		 	</if>
		 </trim>
	 </select>

where(略):去掉開頭,和set類似
set舉例:

	 <!--public void updateEmp(Employee employee);  -->
	 <update id="updateEmpBySet">
	 	<!-- Set標籤的使用 ,去除末尾的,-->
	 	update tbl_employee 
		<set>
			<if test="lastName!=null">
				last_name=#{lastName},
			</if>
			<if test="email!=null">
				email=#{email},
			</if>
			<if test="gender!=null">
				gender=#{gender},
			</if>
		</set>
		where id=#{id} 
	</update>	

set也可由trim代替後的代碼 舉例:

 	<update id="updateEmpByTrim">		
		<trim prefix="set" suffixOverrides=",">
			<if test="lastName!=null">
				last_name=#{lastName},
			</if>
			<if test="email!=null">
				email=#{email},
			</if>
			<if test="gender!=null">
				gender=#{gender}
			</if>
		</trim>
		where id=#{id}
	 </update>	

foreach(難點):

foreach標籤相關屬性介紹:

collection:指定要遍歷的集合(底層是map實現的,因此此集合爲map的value)
也可以利用註解:list類型的參數會特殊處理封裝在map中,map的key就叫list的名字(自動)

item:將當前遍歷出的元素賦值給指定的變量名稱

separator:每個元素之間的分隔符

open:遍歷出所有結果拼接一個開始的字符

close:遍歷出所有結果拼接一個結束的字符

 index:索引。遍歷list的時候是index就是索引,item就是當前值遍歷map的時候index表示的就是map的key,item就是map的值
             

利用底層傳入map集合:

Dao層:
//foreach利用map
public List<Employee> getEmpsByConditionForeachByMap(Map<String, List<Integer>> ids);	


測試:
//查詢操作(foreach 傳入map)
	@Test
	public void test07() throws IOException{
		SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
		SqlSession openSession=sqlSessionFactory.openSession();
		EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);		
		Map<String, List<Integer>> map=new HashMap<String, List<Integer>>();
		List<Integer> ids=new ArrayList<>();
		ids.add(17);
		ids.add(18);
		map.put("ids", ids);
		List<Employee> emps=mapper.getEmpsByConditionForeachByMap(map);
		for (Employee emp : emps) {
			System.out.println(emp);
		}
	}
<!--public List<Employee> getEmpsByConditionForeachByMap(Map<String, List<Integer>> ids);  -->
<select id="getEmpsByConditionForeachByMap" resultType="com.bean.Employee">
	 select * from tbl_employee
	 <foreach collection="ids"  item="item_id" separator=","
	 	open="where id in(" close=")">
	 	#{item_id}
	 </foreach>
</select>

利用註解傳入list集合

Dao層:
//foreach傳入list,利用註解@Param作爲map的key
public List<Employee> getEmpsByConditionForeachByList(@Param("ids") List<Integer> ids);

測試:
//查詢操作(foreach 傳入list)
	@Test
	public void test08() throws IOException{
		SqlSessionFactory sqlSessionFactory=getSqlSessionFactory();
		SqlSession openSession=sqlSessionFactory.openSession();
		EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
		List<Integer> ids=new ArrayList<>();
		ids.add(17);
		ids.add(18);
		List<Employee> emps=mapper.getEmpsByConditionForeachByList(ids);
		for (Employee emp : emps) {
			System.out.println(emp);
		}
	}	
	 <!--public List<Employee> getEmpsByConditionForeach(@Param("ids") List<Integer> ids);  -->
	 <select id="getEmpsByConditionForeachByList" resultType="com.bean.Employee">
	 	select * from tbl_employee
	 	<foreach collection="ids"  item="item_id" separator=","
	 		open="where id in(" close=")">
	 		#{item_id}
	 	</foreach>
	 </select>

 

討論foreach的批量添加操作:

方法一:執行一次sql語句

	 <!--public void addEmps(@Param("emps") List<Employee2> emps); -->
	 <insert id="addEmps">
	 	insert into tbl_employee(last_name,email,gender,d_id) 
		values
		<foreach collection="emps" item="emp" separator=",">
			(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
		</foreach>
	 </insert>

方法二:執行多次sql語句,用分號" ; "分割

	 <!-- 方法二:不推薦 -->
	 <insert id="addEmps2">
		<foreach collection="emps" item="emp" separator=";">
		insert into tbl_employee(last_name,email,gender,d_id) 
		values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
		</foreach>
	 </insert>	

注意:方法二必須添加jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true,才能正常運行(支持分號分割)

上述兩種方法都執行以下測試用例:

	//批量添加(foreach)
	@Test
	public void test09() throws IOException{
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try{
			EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
			List<Employee2> emps = new ArrayList<>();
			emps.add(new Employee2(null, "smith0x1", "[email protected]", "1",new Department(1)));
			emps.add(new Employee2(null, "allen0x1", "[email protected]", "0",new Department(1)));
			mapper.addEmps(emps);
			openSession.commit();
		}finally{
			openSession.close();
		}
	}

Sql片段:

sql標籤作用:抽取可重用的sql片段。方便後面引用  
sql抽取範圍:經常將要查詢的列名,或者插入用的列名抽取出來方便引用

sql標籤相關屬性: 

include來引用已經抽取的sql片段。

include還可以自定義一些property 變量,sql標籤內部就能使用自定義的屬性

sql片段取出include中的property值正確方式${prop},

	<insert id="addEmps3">
	 	insert into tbl_employee(
	 		<include refid="insertColumn">
	 			<property name="test" value="d_id"/>
	 		</include>
	 	) 
	 	values
		<foreach collection="emps" item="emp" separator=",">
			(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
		</foreach>
	 </insert> 

 分析:<insert>標籤中嵌套了 <include>標籤用來引入sql片段,並且定義了<porperty name=“ ”>標籤的name屬性名稱和值,供sql片段使用,例如下面的${test}使用<include>標籤定義的property值。

	  <sql id="insertColumn">
	  	<if test="_databaseId=='oracle'">
	  		employee_id,last_name,email
	  	</if>
	  	<if test="_databaseId=='mysql'">
	  		<!-- last_name,email,gender,d_id -->
	  		last_name,email,gender,${test} //${test}使用<include>標籤定義的值
	  	</if>
	  </sql>

 

補充:

1)bind 元素可以從 OGNL 表達式中創建一個變量並 將其綁定到上下文。比如:
模糊查詢傳入:lastName

	 <!-- 測試bind -->
	 <!--	public List<Employee> getEmpsTestBind(Employee employee);  -->
	  <select id="getEmpsTestBind" resultType="com.bean.Employee">
	  		<!-- bind:可以將OGNL表達式的值綁定到一個變量中,方便後來引用這個變量的值 -->
	  		<!-- bind過程:將取得值拼接成value,在賦值給name -->
	  		<bind name="_lastName" value="'%'+lastName+'%'"/>
	  		select * from tbl_employee where last_name like #{_lastName}
	  </select>

 2)mybatis內置參數

不只是方法傳遞過來的參數可以被用來判斷,取值。
mybatis默認還有兩個內置參數:

_parameter:代表整個參數
單個參數:_parameter就是這個參數。例如:javabean對象屬性--->_parameter.屬性名
多個參數:參數會被封裝爲一個map;_parameter就是代表這個map。

_databaseId:如果配置了databaseIdProvider標籤,databaseId就是代表當前數據庫的別名oracle

	 <!-- 測試兩個內置參數 -->
	 <!--public List<Employee> getEmpsTestInnerParameter(Employee employee);  -->
	  <select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
	  		<if test="_databaseId=='mysql'">
	  			select * from tbl_employee
	  			<if test="_parameter!=null">
	  				where last_name like #{lastName}
	  			</if>
	  		</if>
	  		<if test="_databaseId=='oracle'">
	  			select * from employees
	  			<if test="_parameter!=null">
	  				where last_name like #{_parameter.lastName}
	  			</if>
	  		</if>
	  </select> 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章