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