前言
前面mysql都是通過(guò)靜態(tài)sql進(jìn)行查詢的,但是如果業(yè)務(wù)復(fù)雜的時(shí)候,我們會(huì)遇到引號(hào)問(wèn)題,或者多一個(gè)空格,這就使得sql代碼編寫錯(cuò)誤了,所以為了解決這個(gè)問(wèn)題,我們有了動(dòng)態(tài)sql。
mybatis框架的動(dòng)態(tài)sql技術(shù)是一種根據(jù)特定條件動(dòng)態(tài)拼裝sql語(yǔ)句的功能,它存在的意義是為了解決拼接sql語(yǔ)句字符串時(shí)的痛點(diǎn)問(wèn)題。具體是通過(guò)標(biāo)簽來(lái)實(shí)現(xiàn)的。
動(dòng)態(tài)sql
1.先看一下模塊目錄結(jié)構(gòu)
在類路徑的resources下的mapper包下創(chuàng)建sql.xml文件(共性抽取)
2.物理建模和邏輯建模
這里省略物理建模步驟,要求數(shù)據(jù)庫(kù)的表與pojo類要對(duì)應(yīng)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package pojo; import lombok.allargsconstructor; import lombok.data; import lombok.noargsconstructor; @data @allargsconstructor @noargsconstructor public class employee { private integer empid; private string empname; private double empsalary; } |
3. 引入依賴
把之前的log4j復(fù)制到類路徑resouces下,另外我們引入依賴后的pom.xml如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
<?xml version= "1.0" encoding= "utf-8" ?> <project xmlns= "http://maven.apache.org/pom/4.0.0" xmlns:xsi= "http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation= "http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelversion> 4.0 . 0 </modelversion> <groupid>org.example</groupid> <artifactid>day03-mybatis02-dynamic</artifactid> <version> 1.0 -snapshot</version> <packaging>jar</packaging> <dependencies> <dependency> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> <version> 1.18 . 8 </version> <scope>provided</scope> </dependency> <!-- mybatis核心 --> <dependency> <groupid>org.mybatis</groupid> <artifactid>mybatis</artifactid> <version> 3.5 . 7 </version> </dependency> <!-- junit測(cè)試 --> <dependency> <groupid>junit</groupid> <artifactid>junit</artifactid> <version> 4.12 </version> <scope>test</scope> </dependency> <!-- mysql驅(qū)動(dòng) --> <dependency> <groupid>mysql</groupid> <artifactid>mysql-connector-java</artifactid> <version> 5.1 . 3 </version> <scope>runtime</scope> </dependency> <!-- log4j日志 --> <dependency> <groupid>log4j</groupid> <artifactid>log4j</artifactid> <version> 1.2 . 17 </version> </dependency> </dependencies> </project> |
4.全局配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<?xml version= "1.0" encoding= "utf-8" ?> <!doctype configuration public "-//mybatis.org//dtd config 3.0//en" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration> <!--駝峰映射--> <settings> <setting name= "mapunderscoretocamelcase" value= "true" /> </settings> <!--類型別名映射--> <typealiases> < package name= "pojo" /> </typealiases> <!--環(huán)境配置--> <environments default = "dev" > <environment id= "dev" > <transactionmanager type= "jdbc" ></transactionmanager> <datasource type= "pooled" > <property name= "username" value= "root" /> <property name= "password" value= "888888" /> <property name= "url" value= "jdbc:mysql://localhost:3306/mybatis-example" /> <property name= "driver" value= "com.mysql.jdbc.driver" /> </datasource> </environment> </environments> <!--路徑映射--> <mappers> <mapper resource= "mapper/sql.xml" /> < package name= "mapper" /> </mappers> </configuration> |
注意: 這里有駝峰映射,別名映射,路徑映射和路徑映射。和以前的不同的是,我們這里做了sql語(yǔ)句的共性抽取,所以得加一個(gè)sql的路徑映射 <mapper resource="mapper/sql.xml"/>
。
5.sql共性抽取文件
在類路徑resources下的包mapper下創(chuàng)建一個(gè)sql.xml(因?yàn)槲覀僺ql是要寫在映射文件中,自己本身也是映射文件,所以需要寫在mapper下)。到要用的時(shí)候,在映射路徑文件中需要用到這個(gè)sql語(yǔ)句的地方加入 <include refid="mapper.sql.myselectsql"></include>
。
1
2
3
4
5
6
7
8
9
10
11
12
|
<?xml version= "1.0" encoding= "utf-8" ?> <!doctype mapper public "-//mybatis.org//dtd mapper 3.0//en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace= "mapper.sql" > <sql id= "myselectsql" > select emp_id,emp_name,emp_salary from t_emp </sql> </mapper> |
共性抽取文件也可以不配置,這時(shí)候直接在映射文件中把要執(zhí)行的語(yǔ)句重新編寫就行了。
6.mapper接口
一共有七個(gè)方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package mapper; import org.apache.ibatis.annotations.param; import pojo.employee; import java.util.list; public interface employeemapper { //根據(jù)員工的empid查詢大于該empid的所有員工,如果empid為null,則查詢?nèi)w員工 list<employee> selectemployeelistbyempid(integer empid); /** * 查詢大于傳入的empid并且工資大于傳入的empsalary的員工集合,如果傳入的empid為null,則不考慮empid條件 * 傳入的empsalary為null則不考慮empsalary的條件 */ list<employee> selectemployeelistbyempidandempsalary( @param ( "empid" ) integer empid, @param ( "empsalary" ) double empsalary); /** * 根據(jù)empid更新員工信息,如果某個(gè)值為null,則不更新這個(gè)字段 */ void updateemployee(employee employee); /** * 根據(jù)emp_id查詢員工信息,如果0<emp_id<6,那么就查詢所有大于該emp_id的員工,如果emp_id是大于6,那么就查詢所有小于該emp_id的員工 * 如果是其它情況,則查詢所有員工信息 */ list<employee> selectemployeelist(integer empid); /** * 添加員工信息 */ void insertemployee(employee employee); /** * 批量添加員工集合 */ void insertemployeelist( @param ( "employeelist" ) list<employee> employeelist); /** * 根據(jù)員工的id集合查詢員工集 */ list<employee> selectemployeelistbyempidlist(list<integer> idlist); } |
if
目標(biāo):根據(jù)員工的empid查詢大于該empid的所有員工,如果empid為null,則查詢?nèi)w員工。
dao接口的方法為:
list<employee> selectemployeelistbyempid(integer empid);
靜態(tài)sql:
1
2
3
4
5
|
<select id= "selectemployeelistbyempid" resulttype= "employee" > <include refid= "mapper.sql.myselectsql" ></include> where emp_id>#{empid} </select> |
動(dòng)態(tài)sql:
1
2
3
4
5
6
|
<select id= "selectemployeelistbyempid" resulttype= "employee" > <include refid= "mapper.sql.myselectsql" ></include> < if test= "empid != null" > where emp_id>#{empid} </ if > </select> |
<include refid="mapper.sql.myselectsql"></include>
表示引用抽取出的sql片段,也可以直接寫sql語(yǔ)句。如果是靜態(tài)sql,當(dāng)id為null時(shí),查詢出來(lái)的是空,動(dòng)態(tài)sql則可以查出全部。if標(biāo)簽里面有test屬性名,作為判斷語(yǔ)句。
where
目標(biāo):
- 查詢大于傳入的empid并且工資大于傳入的empsalary的員工集合
- 如果傳入的empid為null,則不考慮empid條件
- 傳入的empsalary為null則不考慮empsalary的條件
dao接口方法:
list<employee> selectemployeelistbyempidandempsalary(@param("empid") integer empid, @param("empsalary") double empsalary);
用if標(biāo)簽的動(dòng)態(tài)sql:
1
2
3
4
5
6
7
8
|
<select id= "selectemployeelistbyempidandempsalary" resulttype= "employee" > <include refid= "mapper.sql.myselectsql" ></include> where < if test= "empid != null" > emp_id>#{empid} </ if > < if test= "empsalary != null" > and emp_salary>#{empsalary} </ if > |
這里可以看到,如果empsalary為空,那么sql語(yǔ)句為select * from t_emp where emp_id >#{empid},但是如果empid為空,那么sql語(yǔ)句為select * from t_emp where and emp_salary>#{empsalary},很明顯這個(gè)是錯(cuò)的,if標(biāo)簽在這里就不適用了。所以我們用where標(biāo)簽,或者trim標(biāo)簽。
where和if的動(dòng)態(tài)sql:
1
2
3
4
5
6
7
8
9
10
11
12
|
<select id= "selectemployeelistbyempidandempsalary" resulttype= "employee" > <include refid= "mapper.sql.myselectsql" ></include> <where> < if test= "empid != null" > emp_id>#{empid} </ if > < if test= "empsalary != null" > and emp_salary>#{empsalary} </ if > </where> </select> |
where標(biāo)簽的作用:
- 在第一個(gè)條件之前自動(dòng)添加where關(guān)鍵字
- 自動(dòng)去掉第一個(gè)條件前的連接符(and、or等等)
trim
trim是修建的意思,其實(shí)就是去頭去尾,這里還是根據(jù)上面那個(gè)方法
trim的動(dòng)態(tài)sql
1
2
3
4
5
6
7
8
9
10
11
12
|
<select id= "selectemployeelistbyempidandempsalary" resulttype= "employee" > <include refid= "mapper.sql.myselectsql" ></include> <trim prefix= "where" prefixoverrides= "and|or" > < if test= "empid != null" > emp_id>#{empid} </ if > < if test= "empsalary != null" > and emp_salary>#{empsalary} </ if > </trim> </select> |
trim標(biāo)簽:
- prefix:指定要?jiǎng)討B(tài)添加的前綴
- suffix屬性:指定要?jiǎng)討B(tài)添加的后綴
- prefixoverrides:指定要?jiǎng)討B(tài)去掉的前綴,使用“|”分隔有可能的多個(gè)值
- suffixoverrides屬性:指定要?jiǎng)討B(tài)去掉的后綴,使用“|”分隔有可能的多個(gè)值
set
目標(biāo):根據(jù)empid更新員工信息,如果某個(gè)值為null,則不更新這個(gè)字段
dao接口方法:
void updateemployee(employee employee);
我們先用上面的trim標(biāo)簽來(lái)解決一下這個(gè)問(wèn)題,
trim的動(dòng)態(tài)sql:
1
2
3
4
5
6
7
8
9
10
11
|
<update id= "updateemployee" > <trim prefix= "set" prefixoverrides= "," > < if test= "empname!=null" > emp_name=#{empname} </ if > < if test= "empsalary!=null" > , emp_salary=#{empsalary} </ if > </trim> where emp_id=#{empid} </update> |
set的動(dòng)態(tài)sql
1
2
3
4
5
6
7
8
9
10
|
<update id= "updateemployee" > update t_emp <set > < if test= "empname!=null" > emp_name=#{empname} </ if > < if test= "empsalary!=null" > , emp_salary=#{empsalary} </ if > </set> |
可以看出
set標(biāo)簽的作用:
- 自動(dòng)在要修改的第一個(gè)字段之前添加set關(guān)鍵字
- 去掉要修改的第一個(gè)字段前的連接符(,)
choose、when、otherwise
目標(biāo):
- 根據(jù)emp_id查詢員工信息,如果0<emp_id<6,那么就查詢所有大于該emp_id的員工
- 如果emp_id是大于6,那么就查詢所有小于該emp_id的員工
- 如果是其它情況,則查詢所有員工信息
dao接口方法:
list<employee> selectemployeelist(integer empid);
動(dòng)態(tài)sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<select id= "selectemployeelist" resulttype= "employee" > <include refid= "mapper.sql.myselectsql" ></include> where <choose> <!--<是<號(hào)的轉(zhuǎn)義字符--> <when test= "empid>0 and empid<6" > emp_id>#{empid} </when> <when test= "empid>6" > emp_id<#{empid} </when> <otherwise> 1 == 1 </otherwise> </choose> </select> |
choose、when、otherwise
相當(dāng)于if ... else
if... else
if ... else
- 如果某一個(gè)when的條件成立,則不會(huì)繼續(xù)判斷后續(xù)的when
- 如果所有的when都不成立,則會(huì)拼接otherwise標(biāo)簽中的內(nèi)容
foreach
目標(biāo)1:批量添加員工信息
dao接口方法:
void insertemployeelist(@param("employeelist") list
employeelist);
1.動(dòng)態(tài)sql
1
2
3
4
5
6
7
8
|
<insert id= "insertemployeelist" > insert into t_emp(emp_name,emp_salary)values <!--collection標(biāo)簽可以寫list,collection, 或者自己自己定義參數(shù)名 @param ( "employeelist" ) list<employee> employeelist--> <foreach collection= "employeelist" separator= "," item= "emp" > (#{emp.empname},#{emp.empsalary}) </foreach> </insert> |
目標(biāo)2:根據(jù)多個(gè)id查詢多個(gè)員工信息
dao接口
list
selectemployeelistbyempidlist(list
idlist);
2.動(dòng)態(tài)sql
1
2
3
4
5
6
|
<select id= "selectemployeelistbyempidlist" resulttype= "employee" > <include refid= "mapper.sql.myselectsql" ></include> <foreach collection= "collection" item= "id" separator= "," open= "where emp_id in (" close= ")" > #{id} </foreach> </select> |
批量查詢:foreach標(biāo)簽
- collection屬性: 表示要遍歷的對(duì)象,如果要遍歷的參數(shù)使用@param注解取名了就使用該名字,如果沒(méi)有取名list,或者collection。
- item屬性: 表示遍歷出來(lái)的元素,我們到時(shí)候要拼接sql語(yǔ)句就得使用這個(gè)元素: 如果遍歷出來(lái)的元素是pojo對(duì)象, 那么我們就通過(guò) #{遍歷出來(lái)的元素.pojo的屬性} 獲取數(shù)據(jù);如果遍歷出來(lái)的元素是簡(jiǎn)單類型的數(shù)據(jù),那么我們就使用 #{遍歷出來(lái)的元素} 獲取這個(gè)簡(jiǎn)單類型數(shù)據(jù)
- separator屬性: 遍歷出來(lái)的元素之間的分隔符
- open屬性: 在遍歷出來(lái)的第一個(gè)元素之前添加前綴
- close屬性: 在遍歷出來(lái)的最后一個(gè)元素之后添加后綴
測(cè)試程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
import mapper.employeemapper; import org.apache.ibatis.io.resources; import org.apache.ibatis.session.sqlsession; import org.apache.ibatis.session.sqlsessionfactory; import org.apache.ibatis.session.sqlsessionfactorybuilder; import org.junit.after; import org.junit.before; import pojo.employee; import java.io.inputstream; import java.util.arraylist; import java.util.list; public class test { private employeemapper employeemapper; private inputstream is; private sqlsession sqlsession; @before public void init() throws exception{ //目標(biāo):獲取employeemapper接口的代理對(duì)象,并且使用該對(duì)象調(diào)用selectemployee(1)方法,然后返回employee對(duì)象 //1. 將全局配置文件轉(zhuǎn)成字節(jié)輸入流 is = resources.getresourceasstream( "mybatisconfig.xml" ); //2. 創(chuàng)建sqlsessionfactorybuilder對(duì)象 sqlsessionfactorybuilder sqlsessionfactorybuilder = new sqlsessionfactorybuilder(); //3. 使用構(gòu)建者模式創(chuàng)建sqlsessionfactory對(duì)象 sqlsessionfactory sqlsessionfactory = sqlsessionfactorybuilder.build(is); //4. 使用工廠模式創(chuàng)建一個(gè)sqlsession對(duì)象 sqlsession = sqlsessionfactory.opensession(); //5. 使用動(dòng)態(tài)代理模式,創(chuàng)建employeemapper接口的代理對(duì)象 employeemapper = sqlsession.getmapper(employeemapper. class ); } @after public void after() throws exception{ //提交事務(wù)!!! sqlsession.commit(); //7. 關(guān)閉資源 is.close(); sqlsession.close(); } @org .junit.test public void testselectemployeelistbyempid(){ system.out.println(employeemapper.selectemployeelistbyempid( null )); } @org .junit.test public void testselectemployeelistbyempidandempsalary(){ system.out.println(employeemapper.selectemployeelistbyempidandempsalary( 2 , 300d)); } @org .junit.test public void testupdateemployee(){ employee employee = new employee( 3 , "celia" , 9000d); employeemapper.updateemployee(employee); } @org .junit.test public void testselectemployeelist(){ system.out.println(employeemapper.selectemployeelist( 7 )); } @org .junit.test public void testinsertemployee(){ employeemapper.insertemployee( new employee( null , "tom" ,300d)); } @org .junit.test public void testinsertemployeelist(){ list<employee> employeelist = new arraylist<>(); for ( int i = 11 ; i <= 20 ; i++) { employeelist.add( new employee( null , "aobama" +i,2000d)); } employeemapper.insertemployeelist(employeelist); } @org .junit.test public void testselectemployeelistbyempidlist(){ list<integer> idlist = new arraylist<>(); idlist.add( 23 ); idlist.add( 33 ); idlist.add( 32 ); idlist.add( 21 ); idlist.add( 22 ); system.out.println(employeemapper.selectemployeelistbyempidlist(idlist)); } } |
到此這篇關(guān)于mybatis 動(dòng)態(tài)sql全面詳解的文章就介紹到這了,更多相關(guān)mybatis 動(dòng)態(tài)sql內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://www.cnblogs.com/jasmine-e/p/15354425.html