04、MyBatis DynamicSQL(Mybatis動態SQL)

来源:https://www.cnblogs.com/CSAH/archive/2020/06/17/13150179.html
-Advertisement-
Play Games

1.動態SQL簡介 動態 SQL是MyBatis強大特性之一. 動態 SQL 元素和使用 JSTL 或其他類似基於 XML 的文本處理器相似. MyBatis 採用功能強大的基於 OGNL 的表達式來簡化操作. 2.if 1).實現DynamicSQL public interface Employ ...


1.動態SQL簡介

  動態 SQL是MyBatis強大特性之一.

  動態 SQL 元素和使用 JSTL 或其他類似基於 XML 的文本處理器相似.

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

 

2.if

 

1).實現DynamicSQL

 

public interface EmployeeMapperDynamicSQL {
	public List<Employee> getEmpsByCondtionIf(Employee employee);
}

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <!-- 查詢員工:攜帶指定欄位查詢條件就帶上該欄位的值 -->
	 <!-- public List<Employee> getEmpsByCondtionIf(Employee employee) -->
	 <select id="getEmpsByCondtionIf" resultType="com.atguigu.mybatis.bean.Employee">
	 	select * from tbl_employee
	 	<!-- where:根據條件包含 where 子句 -->
	 	where
		 	<!-- test:判斷表達式(OGNL) -->
		 	<!-- OGNL語法參照PPT或者官方文檔:http://commons.apache.org/proper/commons-ognl/language-guide.html -->
		 	<!-- 從參數中取值進行判斷,如果遇到特殊符號去寫轉義字元,查W3C HTML ISO-8859-1 參考手冊 -->
		 	<if test="id!=null">
		 		id=#{id}
		 	</if>
		 	<!-- <if test="lastName!=null and lastName!="""> -->
		 	<!-- <if test="lastName!=null && lastName!=''"> -->
		 	<if test="lastName!=null && lastName!=""">
		 		and last_name like #{lastName}
		 	</if>
		 	<if test="email!=null and email.trim()!=""">
		 		 and email=#{email}
		 	</if>
		 	<!-- ognl會進行字元串與數字的轉換判斷  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 		and gender=#{gender}
		 	</if>
	 </select>
</mapper>

  

//			select * from tbl_employee WHERE id=? and last_name like ? and email=?
//			Employee employee  = new Employee(3, "%e%","[email protected]", null);
			//select * from tbl_employee WHERE id=? and last_name like ?
			Employee employee  = new Employee(null, "%e%",null, null);
			List<Employee> emps = mapper.getEmpsByCondtionIf(employee);
			for(Employee emp:emps) {
				System.out.println(emp);
			}

  

2.choose

  有時候,我們不想使用所有的條件,而只是想從多個條件中選擇一個使用.針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句.

 

	public List<Employee> getEmpByConditionChoose(Employee employee);

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <!-- public List<Employee> getEmpByConditionChoose(Employee employee) -->
	 <select id="getEmpByConditionChoose" resultType="com.atguigu.mybatis.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>
</mapper>

  

			//測試choose
			Employee employee  = new Employee(3, "%e%",null, null);
			List<Employee> list = mapper.getEmpByConditionChoose(employee);
			for(Employee emp:list) { 
				System.out.println(emp); 
			}

  

3.trim

1).where

 

	public List<Employee> getEmpsByCondtionTrim(Employee employee);

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <!-- public List<Employee> getEmpsByCondtionTrim(Employee employee) -->
	 <select id="getEmpsByCondtionTrim" resultType="com.atguigu.mybatis.bean.Employee">
	 	select * from tbl_employee
	 	<!-- 後面多出的and或者or where標簽不能解決,我們使用trim定製where元素功能  -->
	 	<!-- 自定義字元串的截取規則 -->
	 	<!-- trim:根據條件包含 where 子句 -->
	 	<!-- trim標簽體中是整個字元串拼串 後的結果 -->
	 	<!-- 通過自定義 trim 元素來定製 where 元素的功能 -->
	 	<!-- prefix:首碼;prefix給拼串後的整個字元串加一個首碼  如:where <===> <trim prefix="where"> -->
	 	<!-- prefixOverrides:首碼覆蓋;去掉整個字元串前面多餘的字元 -->
	 	<!-- suffix:尾碼;suffix給拼串後的整個字元串加一個尾碼 -->
	 	<!-- suffixOverrides:尾碼覆蓋;去掉整個字元串後面多餘的字元 -->
	 	<trim prefix="where" suffixOverrides="and">
		 	<if test="id!=null">
		 		 id=#{id} and
		 	</if>
		 	<if test="lastName!=null && lastName!=""">
		 		 last_name like #{lastName} and
		 	</if>
		 	<if test="email!=null and email.trim()!=""">
		 		 email=#{email} and
		 	</if>
		 	<!-- ognl會進行字元串與數字的轉換判斷  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 		gender=#{gender}
		 	</if>
		 </trim>
	 </select>
</mapper>

  

	@Test
	public void testDynamicSql() throws IOException {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
//			select * from tbl_employee WHERE id=? and last_name like ? and email=?
//			Employee employee  = new Employee(3, "%e%","[email protected]", null);
			//select * from tbl_employee WHERE id=? and last_name like ?
			Employee employee  = new Employee(3, "%e%",null, null);
			List<Employee> emps = mapper.getEmpsByCondtionIf(employee);
			for(Employee emp:emps) {
				System.out.println(emp);
			}
			
			//查詢的時候如果某些條件沒帶可能sql拼裝會有問題
			//1、給where後面加上1=1,以後的條件都and xxx.
			//2、mybatis使用where標簽來將所有的查詢條件包括在內。
				//mybatis就會將where標簽中拼裝的sql,多出來的and或者or去掉
				//where只會去掉第一個多出來的and或者or。

			//測試Trim
			List<Employee> emps2 = mapper.getEmpsByCondtionTrim(employee);
			for(Employee emp:emps2) {
				System.out.println(emp);
			}
			
		} finally {
			//  : handle finally clause
			openSession.close();
		}
	}

  

2).set

①.使用set更新

	public void  updateEmp(Employee employee);

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <update id="updateEmp">
	 	<!-- set:更新拼串  -->
	 	<!-- 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>
</mapper>

  

			//調試set標簽 
			Employee employee = new Employee(1, "Adminn",null, null); 
			mapper.updateEmp(employee);
			openSession.commit();

  

②.使用trim拼串更新

	public void  updateEmp(Employee employee);

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <!-- public void  updateEmp(Employee employee) -->
	 <update id="updateEmp">
	 	<!-- Trim:更新拼串  -->
		update tbl_employee 
		<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>
</mapper>

  

			//調試set標簽 
			Employee employee = new Employee(1, "Adminn",null, null); 
			mapper.updateEmp(employee);
			openSession.commit();

  

4.foreach

 

 

  動態 SQL 的另外一個常用的必要操作是需要對一個集合進行遍歷,通常是在構建 IN 條件語句的時候.

 

  當迭代列表、集合等可迭代對象或者數組時;index是當前迭代的次數,item的值是本次迭代獲取的元素.

  當使用字典(或者Map.Entry對象的集合)時,index是鍵,item是值.

1).MySQL

(1).遍歷記錄

	//查詢員工id'在給定集合中的
	public List<Employee> getEmpsByConditionForeach(@Param("ids")List<Integer> ids);

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <!-- public List<Employee> getEmpsByConditionForeach(List<Integer> ids) -->
	 <select id="getEmpsByConditionForeach" resultType="com.atguigu.mybatis.bean.Employee">
	 	<!-- collection:指定要遍歷的集合;list類型的參數會特殊處理封裝在map中,map的key就是list -->
	 	<!-- item:當前遍歷出的元素賦值給指定的變數 -->
	 	<!-- separator:每個元素之間的分隔符 -->
	 	<!-- open:遍歷出所有結果拼接一個開始的字元 -->
	 	<!-- close:遍歷出所有結果拼接一個結束的字元 -->
	 	<!-- index:索引;遍歷list的時候是index就是索引,item就是當前值;遍歷map的時候index表示的就是map的key,item就是map的值 -->
	 	<!-- #{變數名}:能取出變數的值也就是當前遍歷出的元素 -->
	 	select * from tbl_employee
	 	<foreach collection="ids" item="item_id" separator="," open="where id in(" close=")">
	 		#{item_id}
	 	</foreach>
	 </select>
</mapper>

  

			//測試foreach
			List<Employee> list = mapper.getEmpsByConditionForeach(Arrays.asList(1,2,3,4));
			for(Employee emp : list) {
				System.out.println(emp);
			}

  

(2).批量保存記錄1

	public void addEmps(@Param("emps")List<Employee> emps);

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <!-- 批量保存數據 -->
	 <!-- MySQL下批量保存:可以foreach遍歷   mysql支持values(),(),()語法 -->
	 <!-- public void addEmps(@Param("emps")List<Employee> emps) -->
	 <!-- insert 方式一 -->
	 <!-- 推薦使用inert 方式一 -->
 	 <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> 
</mapper>

  

			List<Employee> emps = new ArrayList<>();
			emps.add(new Employee(null, "smith", "[email protected]", "1",new Department(1)));
			emps.add(new Employee(null, "allen", "[email protected]", "0",new Department(1)));
			mapper.addEmps(emps);
			openSession.commit();

  

(3).批量保存記錄2

	public void addEmps(@Param("emps")List<Employee> emps);

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <!-- insert 方式二 -->
	 <!-- public void addEmps(@Param("emps")List<Employee> emps) -->
	 <!-- 這種方式需要資料庫連接屬性allowMultiQueries=true;
	 	這種分號分隔多個sql可以用於其他的批量操作(刪除,修改) -->
	  <insert id="addEmps">
	 	<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> 
</mapper>

  

			List<Employee> emps = new ArrayList<>();
			emps.add(new Employee(null, "smith", "[email protected]", "1",new Department(1)));
			emps.add(new Employee(null, "allen", "[email protected]", "0",new Department(1)));
			mapper.addEmps(emps);
			openSession.commit();

  

2).Oracle

(1).批量保存1

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <insert id="addEmps" databaseId="oracle">
	 	<!-- oracle第一種批量方式 -->
	 	<!-- <foreach collection="emps" item="emp" open="begin" close="end;">
	 		insert into employees(employee_id,last_name,email) 
			    values(employees_seq.nextval,#{emp.lastName},#{emp.email});
	 	</foreach> 
	 </insert>
</mapper>

(2).批量保存2

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <insert id="addEmps" databaseId="oracle">
	 	<!-- oracle第二種批量方式  -->
	 	insert into employees(
	 		<!-- 引用外部定義的sql -->
	 		<include refid="insertColumn">
	 			<property name="testColomn" value="abc"/>
	 		</include>
	 	)
	 			<foreach collection="emps" item="emp" separator="union"
	 				open="select employees_seq.nextval,lastName,email from("
	 				close=")">
	 				select #{emp.lastName} lastName,#{emp.email} email from dual
	 			</foreach>
	 </insert>
</mapper>

  

5.bind

  bind 元素可以從 OGNL 表達式中創建一個變數並將其綁定到上下文.

 

1).bind

  若在 mybatis 配置文件中配置了 databaseIdProvider , 則可以使用 “_databaseId”變數,這樣就可以根據不同的資料庫廠商構建特定的語句.

	public List<Employee> getEmpsTestInnerParameter(Employee employee);

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <!-- public List<Employee> getEmpsTestInnerParameter(Employee employee) -->
	 <!-- mybatis預設還有兩個內置參數:_parameter|_databaseId -->
	 <!-- _parameter:代表整個參數;單個參數:_parameter就是這個參數;多個參數:參數會被封裝為一個map,_parameter就是代表這個map -->
	 <!-- _databaseId:如果配置了databaseIdProvider標簽;_databaseId就是代表當前資料庫的別名 -->
	 <select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
		<!-- bind:可以將OGNL表達式的值綁定到一個變數中,方便後來引用這個變數的值 -->
	  		<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>
</mapper>

  

	@Test
	public void testInnerParam() throws IOException{
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try{
			EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
			Employee employee2 = new Employee();
			employee2.setLastName("%e%");
			List<Employee> list = mapper.getEmpsTestInnerParameter(employee2);
			for (Employee employee : list) {
				System.out.println(employee);
			}
		}finally{
			openSession.close();
		}
	}

  

2).SQL片段

	public void addEmps(@Param("emps")List<Employee> emps);

  

<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL">
	 <!-- insert 方式三 -->
	<insert id="addEmps">
		insert into tbl_employee(
			<include refid="insertColumn"></include>
	 	) 
		values
		<foreach collection="emps" item="emp" separator=",">
			(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
		</foreach>
	</insert>
	<!-- 抽取可重用的sql片段;方便後面引用  -->
	<!-- 1、sql抽取:經常將要查詢的列名,或者插入用的列名抽取出來方便引用 -->
	<!-- 2、include來引用已經抽取的sql -->
	<!-- 3、include還可以自定義一些property,sql標簽內部就能使用自定義的屬性 -->
	<!-- include-property:取值的正確方式${prop} #{不能使用這種方式} -->  			
	<sql id="insertColumn">
		<if test="_databaseId=='oracle'">
			employee_id,last_name,email
		</if>
		<if test="_databaseId=='mysql'">
			last_name,email,gender,d_id
		</if>
	</sql>
</mapper>

  

	@Test
	public void testBatchSave() throws IOException {
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			EmployeeMapperDynamicSQL mapper = openSession.getMapper(EmployeeMapperDynamicSQL.class);
			List<Employee> emps = new ArrayList<>();
			emps.add(new Employee(null, "smith", "[email protected]", "1",new Department(1)));
			emps.add(new Employee(null, "allen", "[email protected]", "0",new Department(1)));
			mapper.addEmps(emps);
			openSession.commit();
		}finally {
			openSession.close();
		}
	}

6.OGNL

 

參考文檔:http://commons.apache.org/proper/commons-ognl/language-guide.html

https://mybatis.org/mybatis-3/zh/dynamic-sql.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 只要接觸過前端,都會指導web前端的知識主要由三部分組成:分別為靜態html,樣式css,動態javascript(簡稱js)這三大部分組成。其三部分組成的一個體系的複雜程度不亞於其他一門技術的複雜程度。當然對於跟我一樣厲害的那些web前端來說那就是小菜一碟,但是很多人都只學了錶面,基礎部分,很多重 ...
  • 在日常開發中,項目中的菜單欄都是已經實現好了的。如果需要添加新的菜單,只需要在`路由配置`中新增一條路由,就可以實現菜單的添加。 相信大家和我一樣,有時候會躍躍欲試自己去實現一個菜單欄。那今天我就將自己實現的菜單欄的整個思路和代碼分享給大家。 ...
  • 1.let 和 const 命令 在es5時,只有兩種變數聲明,var 和function。在es6中新增了四種let和const,以及另外兩種聲明import和class。 我們先講解let和const,後續會補充import和class (1)let 我們先來看基本語法 { let a = 10 ...
  • 目錄: 1.擴展運算符2.Array.form()3.Array.of()4.數組實例的copyWithin()5.數組實例的find()和findIndex()6.數組實例的fill()7.數組實例的entries(),keys(),vlaues()8.數組實例的includes()9.數組的空位 ...
  • 也許你瞧不起以前的 css ,但是你不該再輕視眼下的 css 。近年來 css 的變數系統已逐步得到各大瀏覽器廠商支持,自定義選擇器等強勢襲來,嵌套系統/模塊系統也在路上…為了更好的掌握 css 這門語言,很有必要把之前零零散散的 css 知識回爐重造下。 css 作為一門語言而,也有其繼承原理,雖 ...
  • 將一些零散的知識點進行整理, 以便加深理解,方便查閱,也希望能幫到大家。 一、負載均衡演算法 1. 隨機 完全隨機 通過系統隨機函數,根據後端伺服器列表的大小值來隨機選擇其中一臺進行訪問。由概率統計理論可以得知,隨著調用量的增大,其實際效果越來越接近於平均分配流量到每一臺後端伺服器,也就是輪詢的效果。 ...
  • /** * 1.模式定義: * 過濾器(Filter Pattern)又稱為標準模式(Criteria Pattern)是一種設計模式,這種模式允許開發人員使用不同的標準來過濾一組對象, * 通過預算邏輯以解耦的方式將他們聯繫起來。這種類型的設計模式屬於結構模型,說白了,就是按條件篩選一組對象出來。 ...
  • 背景 之前做過一個項目,資料庫存儲採用的是mysql。當時面臨著業務指數級的增長,存儲容量不足。當時採用的措施是 1>短期解決容量的問題 mysql從5.6升級5.7,因為數據核心且重要,資料庫主從同步採用的是全同步, 利用5.7並行複製新特性,減少了主從同步的延遲,提高了吞吐量。 當時業務量高峰是 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...