MyBatis(4)动态SQL
MyBatis 的強(qiáng)大特性之一便是它的動(dòng)態(tài) SQL。如果你有使用 JDBC 或其它類似框架的經(jīng)驗(yàn),你就能體會(huì)到根據(jù)不同條件拼接 SQL 語句的痛苦。例如拼接時(shí)要確保不能忘記添加必要的空格,還要注意去掉列表最后一個(gè)列名的逗號(hào)。利用動(dòng)態(tài) SQL 這一特性可以徹底擺脫這種痛苦。
? ? ?雖然在以前使用動(dòng)態(tài) SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射語句中的強(qiáng)大的動(dòng)態(tài) SQL 語言得以改進(jìn)這種情形。
? ? ?動(dòng)態(tài) SQL 元素和 JSTL 或基于類似 XML 的文本處理器相似。在 MyBatis 之前的版本中,有很多元素需要花時(shí)間了解。MyBatis 3 大大精簡(jiǎn)了元素種類,現(xiàn)在只需學(xué)習(xí)原來一半的元素便可。MyBatis 采用功能強(qiáng)大的基于 OGNL 的表達(dá)式來淘汰其它大部分元素。
--->if --->choose(when,otherwise) --->trim(where,set) --->foreach 此文章及以后不帶結(jié)果的截圖,影響整體文章的布局美感!!! 其他的一些可以簡(jiǎn)單看一下之前的博文! 首先來看看本次工程的目錄吧:mybatis-config.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><properties resource="db.properties" ></properties><environments default="development"><environment id="development"><transactionManager type="JDBC" /><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></dataSource></environment></environments><mappers><mapper resource="DynamicSQL.xml"/></mappers> </configuration>?Employee.java(getter&setter&toString)
public class Employee {private int id;private String name;private String gender;private String email;private Department dept; }?現(xiàn)在基本的布局已經(jīng)完成!!
?
1)if
A.在DynamicMapper.java接口中
//攜帶了哪個(gè)字段的查詢條件就攜帶這個(gè)字段的值public List<Employee> getEmpByIf(Employee emp);?
在Dynamic'SQl.xml文件 <!-- if --><!-- 查詢員工,要求,攜帶了那個(gè)字段查詢條件就帶上那個(gè)字段的字段值 --><!-- public List<Employee> getEmpByIf(Employee emp); --><select id="getEmpByIf" resultType="com.MrChengs.bean.Employee">select * from testwhere<!-- test:判斷表達(dá)式(OGNL) --><!-- OGNL:apache官方文檔有明確的解釋說明 --><!-- 從參數(shù)中取值進(jìn)行判斷不是數(shù)據(jù)庫(kù)中取值 --><!-- 特殊字符應(yīng)該寫轉(zhuǎn)義字符 --><if test="id!=null">id=#{id}</if><if test="name!=null and name!=''">and name like #{name}</if><if test="email!=null and email.trim()!=''">and email like #{email}</if></select> 在這個(gè)文件的內(nèi)容簡(jiǎn)要的進(jìn)行說明一下: and name like #{name} 這里的紅色的name是我們查詢的name值,不是數(shù)據(jù)庫(kù)中的name #{name}是把我們手動(dòng)輸入的紅色name傳遞過去,進(jìn)行數(shù)據(jù)庫(kù)的查詢 測(cè)試類: public SqlSessionFactory getSqlSessionFactory() throws IOException{String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream);}@Testpublic void test() throws IOException {SqlSessionFactory sessionFactory = getSqlSessionFactory();SqlSession session = sessionFactory.openSession();try{DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class);//傳入的紅色name值進(jìn)行數(shù)據(jù)庫(kù)的查詢Employee emp = new Employee(5, "%Mr%", "boy", "%1287%");List<Employee> emps = mapper.getEmpByIf(emp);System.out.println(emps);}finally{session.close();}}?查詢之后的顯示代碼
DEBUG 10-02 12:13:49,806 ==> Preparing: select * from test where id=? and name like ? and email like ? (BaseJdbcLogger.java:159) DEBUG 10-02 12:13:49,843 ==> Parameters: 5(Integer), %Mr%(String), %1287%(String) (BaseJdbcLogger.java:159) DEBUG 10-02 12:13:49,873 <== Total: 1 (BaseJdbcLogger.java:159) [Employee [id=5, name=MrChengs, gender=boy, email=1287xxxxxx@xx.com, dept=null]]?
B.在查詢的時(shí)候,如果某些時(shí)候某些條件沒帶可能導(dǎo)致sql拼裝有問題 實(shí)例: <select id="getEmpByIf" resultType="com.MrChengs.bean.Employee">select * from testwhere<!-- test:判斷表達(dá)式(OGNL) --><!-- OGNL:apache官方文檔有明確的解釋說明 --><!-- 從參數(shù)中取值進(jìn)行判斷不是數(shù)據(jù)庫(kù)中取值 --><!-- 特殊字符應(yīng)該寫轉(zhuǎn)義字符 --><!--此時(shí)我們假設(shè)忘記把id傳進(jìn)來 --><if test="name!=null and name!=''">and name like #{name}</if><if test="email!=null and email.trim()!=''">and email like #{email}</if></select>?look:
show message:DEBUG 10-02 12:18:30,831 ==> Preparing: select * from test where and name like ? and email like ?(BaseJdbcLogger.java:159)
?
solution ①:??where 1=1 <select id="getEmpByIf" resultType="com.MrChengs.bean.Employee">select * from test<!-- 加入固定的條件,怎么拼裝都行 -->where 1=1<!-- test:判斷表達(dá)式(OGNL) --><!-- OGNL:apache官方文檔有明確的解釋說明 --><!-- 從參數(shù)中取值進(jìn)行判斷不是數(shù)據(jù)庫(kù)中取值 --><!-- 特殊字符應(yīng)該寫轉(zhuǎn)義字符 --><if test="name!=null and name!=''">and name like #{name}</if><if test="email!=null and email.trim()!=''">and email like #{email}</if></select>?
solution ②:使用<where></where>? 只會(huì)去掉一個(gè)and? 或者or <select id="getEmpByIf" resultType="com.MrChengs.bean.Employee">select * from test<where><!-- test:判斷表達(dá)式(OGNL) --><!-- OGNL:apache官方文檔有明確的解釋說明 --><!-- 從參數(shù)中取值進(jìn)行判斷不是數(shù)據(jù)庫(kù)中取值 --><!-- 特殊字符應(yīng)該寫轉(zhuǎn)義字符 --><if test="name!=null and name!=''">and name like #{name}</if><if test="email!=null and email.trim()!=''">and email like #{email}</if> </where></select>?注意使用and
?
2.使用trim標(biāo)簽進(jìn)行,字符串截取
先看一個(gè)案例的錯(cuò)誤代碼展示: DynamicSQLMapper.java //測(cè)試Trimpublic List<Employee> getEmpByIfTrim(Employee emp);?在DynamicSQL.xml
<!-- 測(cè)試Trim() --><!-- public List<Employee> getEmpByIfTrim(Employee emp); --><select id="getEmpByIfTrim" resultType="com.MrChengs.bean.Employee">select * from testwhere<if test="id!=null">id=#{id} and</if><if test="name!=null and name!=''">name like #{name} and</if><if test="email!=null and email.trim()!=''">email like #{email}</if></select>?
假設(shè)我們此時(shí)傳參為name屬性一個(gè) @Testpublic void testgetEmpByIfTrim() throws IOException {SqlSessionFactory sessionFactory = getSqlSessionFactory();SqlSession session = sessionFactory.openSession();try{DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); Employee emp = new Employee("%Mr%", null, null);List<Employee> emps = mapper.getEmpByIfTrim(emp);System.out.println(emps);}finally{session.close();}}?拼串結(jié)果
DEBUG 10-02 13:31:59,995 ==> Preparing: select * from test where id=? and name like ? and?
開始使用trim標(biāo)簽:(一些用法都在注釋中,請(qǐng)注意看注釋)
<!-- 測(cè)試Trim() --><!-- public List<Employee> getEmpByIfTrim(Employee emp); --><select id="getEmpByIfTrim" resultType="com.MrChengs.bean.Employee">select * from test<!-- prefix:前綴, trim標(biāo)簽體中是整個(gè)字符串拼串后的結(jié)果 給拼串后的整體字符串加一個(gè)前綴--><!-- prefixOverrides:前綴覆蓋, 去點(diǎn)整個(gè)前綴前面多余的字符串 --><!-- suffix:后綴, 給拼串后的整個(gè)字符串加一個(gè)后綴 --><!-- suffixOverrides:后綴覆蓋,去掉整個(gè)字符串后面多余的字符串 -->
<trim prefix="where" suffixOverrides="and"><if test="name!=null and name!=''">name like #{name} and</if><if test="email!=null and email.trim()!=''">email like #{email} and</if><if test="gender!=null">gender=#{gender}</if></trim></select>
?測(cè)試:
public void testgetEmpByIfTrim() throws IOException {SqlSessionFactory sessionFactory = getSqlSessionFactory();SqlSession session = sessionFactory.openSession();try{DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class);Employee emp = new Employee("%Mr%", null, null);List<Employee> emps = mapper.getEmpByIfTrim(emp);System.out.println(emps);}finally{session.close();}}?結(jié)果拼串:
DEBUG 10-02 13:43:25,216 ==> Preparing: select * from test where name like ? (BaseJdbcLogger.java:159) DEBUG 10-02 13:43:25,266 ==> Parameters: %Mr%(String) (BaseJdbcLogger.java:159)?注意:在測(cè)試id的時(shí)候,不寫則默認(rèn)為零,博主自己測(cè)試的時(shí)候遇到的,所以把id的查詢條件拿掉了!
3.choose分支選擇 如果帶了id使用id進(jìn)行查詢,帶了name就是用name進(jìn)行查詢 只能使用一個(gè)進(jìn)行查詢 接口類的代碼: //測(cè)試choosepublic List<Employee> getEmpBychoose(Employee emp);?DynamicSQL.xml:
<!-- choose --><!-- 如果帶了id使用id進(jìn)行查詢,帶了name就是用name進(jìn)行查詢,只能使用一個(gè)進(jìn)行查詢 --><!-- public List<Employee> getEmpBychoose(Employee emp); --><select id="getEmpBychoose" resultType="com.MrChengs.bean.Employee">select * from test<where><choose><when test="name!=null">name like #{name}</when> <when test="email!=null">email = #{email}</when><when test="id!=null">id=#{id}</when> <otherwise>d_id=1</otherwise></choose></where></select>?測(cè)試代碼:
//測(cè)試choose @Testpublic void testgetEmpBychoose() throws IOException {SqlSessionFactory sessionFactory = getSqlSessionFactory();SqlSession session = sessionFactory.openSession();try{DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); Employee emp = new Employee("%Mr%", null, null);emp.setId(5);List<Employee> emps = mapper.getEmpBychoose(emp);System.out.println(emps);}finally{session.close();}}?結(jié)果:
DEBUG 10-02 14:07:35,311 ==> Preparing: select * from test WHERE name like ? (BaseJdbcLogger.java:159) DEBUG 10-02 14:07:35,363 ==> Parameters: %Mr%(String) (BaseJdbcLogger.java:159)?此時(shí)我們不僅傳入了name同時(shí)還傳入了id,但是拼串之后是使用name進(jìn)行查詢的
?
?
3.更新
A.<set></set>版本 在接口中: //更新方法public void updataEmp(Employee emp);?
?在DynamicSQl.xml文件:
?
<!-- update更新 --><!-- 更新 --><!-- public void updataEmp(Employee emp); --><update id="updataEmp">update test<set><if test="name!=null">name=#{name},</if><if test="email!=null"> email=#{email},</if><if test="gender!=null">gender=#{gender},</if></set>where id=#{id}</update>?
?使用<set>標(biāo)簽,可以自動(dòng)為我們解決存在的? ? ”,“? ?問題
測(cè)試: //更新upddate @Testpublic void testgetEmpupdate() throws IOException {SqlSessionFactory sessionFactory = getSqlSessionFactory();SqlSession session = sessionFactory.openSession();try{DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class); Employee emp = new Employee("MrChengsR", "gril", null);emp.setId(7);mapper.updataEmp(emp);System.out.println(emp);session.commit();}finally{session.close();}}?此時(shí)修改數(shù)據(jù)成功
B.<trim><trim> version 僅僅是修改xml文件,其余的都不變 <update id="updataEmp">update test<trim prefix="set" suffixOverrides=","><if test="name!=null">name=#{name},</if><if test="email!=null"> email=#{email},</if><if test="gender!=null">gender=#{gender},</if></trim>where id=#{id}</update>?
4.foreach
A)foreach: DynamicSQLMapper.java //foreachpublic List<Employee> getEmpsByCollection(List<Integer> list);?DynamicSQL.xml
<!-- foreach: --><!-- public List<Employee> getEmpsByCollection(Employee emp); --><select id="getEmpsByCollection" resultType="com.MrChengs.bean.Employee" >select * from test where id in(<!-- collection:指定遍歷的集合 --><!-- list類型的參數(shù)會(huì)做特殊的處理封裝在map中,map的key叫l(wèi)ist --><!-- item:將當(dāng)前遍歷出的元素賦值給指定的變量 --><!-- #{變量名} 就能取出當(dāng)前遍歷的元素 --><!-- separator:每個(gè)元素之間的分隔符 此時(shí)是in(a,b,c,d)這里面的 , --><!-- open:遍歷出所有結(jié)果拼接一個(gè)開始的字符 --><!-- close:便利的所有結(jié)果拼出結(jié)尾 --><!-- index:遍歷list是索引,遍歷map就是map的key --><foreach collection="list" item="item_id" separator=",">#{item_id}</foreach>)</select>?
測(cè)試類: @Testpublic void testgetEmpForeach() throws IOException {SqlSessionFactory sessionFactory = getSqlSessionFactory();SqlSession session = sessionFactory.openSession();try{DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class);List<Employee> emps = mapper.getEmpsByCollection(Arrays.asList(5,7,8));for(Employee emp : emps){System.out.println(emp);}}finally{session.close();}}?得到結(jié)果:
DEBUG 10-02 19:16:01,838 ==> Preparing: select * from test where id in( ? , ? , ? ) (BaseJdbcLogger.java:159) DEBUG 10-02 19:16:01,887 ==> Parameters: 5(Integer), 7(Integer), 8(Integer) (BaseJdbcLogger.java:159) DEBUG 10-02 19:16:01,909 <== Total: 3 (BaseJdbcLogger.java:159) Employee [id=5, name=MrChengs, gender=boy, email=xxxxxxxx@qq.com, dept=null] Employee [id=7, name=MrChengs, gender=gril, email=zhangsan@qq.com, dept=null] Employee [id=8, name=MrChen, gender=gril, email=xxxxxx@xx.xxx, dept=null]?
?
?
B.批量保存
方法1: 接口類中: //批量存取public void addEmps(@Param("emps")List<Employee> employee);?
?xml文件:
?
<!-- //批量存取--><!-- public void addEmps(@Param("emps")Employee employee); --><insert id="addEmps">insert into test(name,gender,email,d_id)values<foreach collection="emps" separator="," item="emp"> <!-- 傳參數(shù)之前是我們new的一個(gè)對(duì)象,傳參數(shù)之后是插入數(shù)據(jù)庫(kù)的數(shù)據(jù) -->(#{emp.name},#{emp.gender},#{emp.email},#{emp.dept.id})</foreach></insert>?
?實(shí)現(xiàn)類:
//批量存取 @Testpublic void testgetEmpaddEmps() throws IOException {SqlSessionFactory sessionFactory = getSqlSessionFactory();SqlSession session = sessionFactory.openSession();try{DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class);List<Employee> employee = new ArrayList<Employee>();employee.add(new Employee("Ma", "gril", "Ma@Ma", new Department(1)));employee.add(new Employee("Mb", "boy", "Mb@Mb", new Department(2)));mapper.addEmps(employee);session.commit();}finally{session.close();}} 此時(shí)是成功插入數(shù)據(jù) 方法二: <!-- 方法二 --><!-- 需要加上 --> <!-- jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true --><insert id="addEmps"><foreach collection="emps" separator=";" item="emp">insert into test(name,gender,email,d_id)values(#{emp.name},#{emp.gender},#{emp.email},#{emp.dept.id})</foreach></insert>?其余不變可以進(jìn)行測(cè)試
c.兩個(gè)重要的參數(shù) <!-- 兩個(gè)重要的參數(shù) --> <!-- _parameter:代表整個(gè)參數(shù),單個(gè)參數(shù)就是這個(gè)參數(shù),多個(gè)參數(shù)就是封裝成的map --> <!-- _databaseId:配置了databaseIdProvider標(biāo)簽,就是代表當(dāng)前數(shù)據(jù)庫(kù)的別名 --> _databaseId: mybatis-config.xml <databaseIdProvider type="DB_VENDOR"><property name="MySQL" value="mysql"/><property name="Oracle" value="oracle"/></databaseIdProvider>?接口類中
//測(cè)試兩個(gè)屬性public List<Employee> getEmpselect();?DynamicMapper.xml
<!-- 兩個(gè)重要的參數(shù) --><!-- _parameter:代表整個(gè)參數(shù),單個(gè)參數(shù)就是這個(gè)參數(shù),多個(gè)參數(shù)就是封裝成的map --><!-- _databaseId:配置了databaseIdProvider標(biāo)簽,就是代表當(dāng)前數(shù)據(jù)庫(kù)的別名 --><!-- public Employee getEmpselect(int id); --><!-- 修改if中的test條件即可實(shí)現(xiàn)不同數(shù)據(jù)庫(kù)之間的查詢 --><select id="getEmpselect" resultType="com.MrChengs.bean.Employee" databaseId="mysql"><if test="_databaseId=='mysql'">select * from test</if><if test="_databaseId=='oracle'">select * from test</if></select>?測(cè)試類:
//兩個(gè)重要的參數(shù) @Testpublic void testgetEmpselect() throws IOException {SqlSessionFactory sessionFactory = getSqlSessionFactory();SqlSession session = sessionFactory.openSession();try{DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class);List<Employee> emps= mapper.getEmpselect();for(Employee emp : emps){System.out.println();}}finally{session.close();}}?
此時(shí)可以成功查詢數(shù)據(jù)!! _parameter 在接口類中:把剛剛測(cè)試代碼加上id //測(cè)試兩個(gè)屬性public List<Employee> getEmpselect(int id);?在xnl文件中:
<!-- public Employee getEmpselect(int id); --><select id="getEmpselect" resultType="com.MrChengs.bean.Employee" databaseId="mysql"><if test="_databaseId=='mysql'">select * from test<if test="_parameter!=null">where id=#{id}</if></if><if test="_databaseId=='oracle'">select * from test</if></select>?
測(cè)試類: @Testpublic void testgetEmpselect() throws IOException {SqlSessionFactory sessionFactory = getSqlSessionFactory();SqlSession session = sessionFactory.openSession();try{ DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class);List<Employee> emps= mapper.getEmpselect(5);System.out.println(emps);}finally{session.close();}} 此時(shí)的查詢成功!!! D.bind標(biāo)簽的使用 接口類中: //測(cè)試兩個(gè)屬性//public List<Employee> getEmpselect();//public List<Employee> getEmpselect(int id);public List<Employee> getEmpselect(Employee em);?
xml文件: <select id="getEmpselect" resultType="com.MrChengs.bean.Employee" databaseId="mysql"> <!-- bind:可以將OGNL表達(dá)式的值綁定到一個(gè)變量中,方便引用這個(gè)變量的值 --> ???????????<!-- name :是我們指定的綁定參數(shù)--> ???????????<!-- value :指定參數(shù)的值 --> <bind name="_name" value="'%'+name+'%'"/> <if test="_databaseId=='mysql'"> select * from test <if test="_parameter!=null"> where name like #{_name} </if> </if> <if test="_databaseId=='oracle'"> select * from test </if> </select>?測(cè)試類:
@Testpublic void testgetEmpselect() throws IOException {SqlSessionFactory sessionFactory = getSqlSessionFactory();SqlSession session = sessionFactory.openSession();try{DynamicSQLMapper mapper = session.getMapper(DynamicSQLMapper.class);//List<Employee> emps= mapper.getEmpselect();//List<Employee> emps= mapper.getEmpselect(5);Employee emp = new Employee();emp.setName("M");List<Employee> emps= mapper.getEmpselect(emp);System.out.println(emps);}finally{session.close();}}?
?
E.SQL標(biāo)簽
<!-- <include refid=""></include> --> <!-- SQL:抽取可重用的sql字段,方便后面引用 --> <!-- include:就是引用外部標(biāo)簽 --> <!-- ???1.sql抽取:經(jīng)常要查詢的列名,或者插入用的列名抽取出來方便引用 ???????????2.include來引用已經(jīng)抽取的sql ???????????3.include還可以自定義一些property,sql標(biāo)簽內(nèi)部只能使用自定義的屬性 ???????????????? include-property:取值正確方式? ${prop} ???????????????? #{不可以使用這種方式} --> <sql id=""> <!-- 同時(shí)這里面還可以使用?? if進(jìn)行判斷 --> <if test=""></if> </sql>轉(zhuǎn)載于:https://www.cnblogs.com/Mrchengs/p/9741325.html
總結(jié)
以上是生活随笔為你收集整理的MyBatis(4)动态SQL的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Promise-Polyfill源码解析
- 下一篇: Node.js 基金会和 JS 基金会准