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