wordpress 圖片被壓縮seo包年服務(wù)
- 0.MyBatis執(zhí)行流程
- 1.第一個MyBatis查詢
- 1.創(chuàng)建數(shù)據(jù)庫和表
- 1.2.添加MyBatis框架依賴【新項目】
- 1.3.添加MyBatis框架依賴【舊項目】
- 1.4.配置連接數(shù)據(jù)庫
- 1.5.配置MyBatis的XML路徑
- 2.MyBatis模式開發(fā)
- 2.1 添加MyBatis的xml配置
- 3.增查改刪(CRUD)
- 5.1.增加操作
- 5.2.修改操作
- 5.3 刪除操作
- 6.查詢操作
- 6.1單表查詢
- 6.2 參數(shù)占位符 #{} 與 ${} 區(qū)別
- 6.2.1.SQL注入問題
- 6.2.2 like查詢
- 6.2.3 屬性名和字段名不一致
- 6.3 resultType
- 6.3.1 resultMap
- 6.3.2 多表查詢
- 7.動態(tài)SQL
- 7.1 < if >標(biāo)簽
- 7.2 < trim >標(biāo)簽
- 7.3 < where >標(biāo)簽
- 7.4 < set >標(biāo)簽
- 7.5 < foreach >標(biāo)簽
- MyBatis是什么?
MyBatis 是?款優(yōu)秀的持久層框架,它?持?定義 SQL、存儲過程以及?級映射。MyBatis 去除了?乎所有的 JDBC 代碼以及設(shè)置參數(shù)和獲取結(jié)果集的?作。MyBatis 可以通過簡單的 XML 或注解來配置和映射原始類型、接?和 Java POJO(Plain Old Java Objects,普通?式 Java 對象)作為數(shù)據(jù)庫中的記錄。通過使用MyBatis,開發(fā)人員可以方便地執(zhí)行CRUD操作(創(chuàng)建、讀取、更新和刪除),以及復(fù)雜的數(shù)據(jù)庫查詢和存儲過程的調(diào)用。
【MyBatis官網(wǎng)】
簡單來說,MyBatis是一個簡單、靈活和強大的持久層框架和數(shù)據(jù)庫交互的工具,廣泛應(yīng)用于Java開發(fā)中,使得數(shù)據(jù)訪問變得更加便捷和高效。
0.MyBatis執(zhí)行流程
大概流程:前端發(fā)生Ajax請求給控制器,控制器調(diào)用服務(wù)層,服務(wù)層進行編排,服務(wù)層調(diào)用mybatis,mybatis調(diào)用數(shù)據(jù)庫,再逐層返回。
MyBatis:在interface中聲明方法,在xml中實現(xiàn)方法。mybatis是基于這兩個實現(xiàn)的。
1.第一個MyBatis查詢
MyBatis 也是?個 ORM 框架,ORM(Object Relational Mapping),即對象關(guān)系映射。在?向
對象編程語?中,將關(guān)系型數(shù)據(jù)庫中的數(shù)據(jù)與對象建?起映射關(guān)系,進??動的完成數(shù)據(jù)與對象的互相轉(zhuǎn)換:
-
將輸?數(shù)據(jù)(即傳?對象)+SQL 映射成原? SQL
-
將結(jié)果集映射為返回對象,即輸出對象ORM 把數(shù)據(jù)庫映射為對象:
- 數(shù)據(jù)庫表(table)–> 類(class)
- 記錄(record,?數(shù)據(jù))–> 對象(object)
- 字段(field) --> 對象的屬性(attribute)
?般的 ORM 框架,會將數(shù)據(jù)庫模型的每張表都映射為?個 Java 類。
也就是說使? MyBatis 可以像操作對象?樣來操作數(shù)據(jù)庫中的表,可以實現(xiàn)對象和數(shù)據(jù)庫表之間
的轉(zhuǎn)換。
1.創(chuàng)建數(shù)據(jù)庫和表
打開MySQL客戶端進行登錄后,直接拷貝下面代碼復(fù)制粘貼就行。
代碼如下:
-- 創(chuàng)建數(shù)據(jù)庫
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8mb4;-- 使用數(shù)據(jù)數(shù)據(jù)
use mycnblog;-- 創(chuàng)建表[用戶表]
drop table if exists userinfo;
create table userinfo(id int primary key auto_increment,username varchar(100) not null,password varchar(32) not null,photo varchar(500) default '',createtime timestamp default current_timestamp,updatetime timestamp default current_timestamp,`state` int default 1
) default charset 'utf8mb4';-- 創(chuàng)建文章表
drop table if exists articleinfo;
create table articleinfo(id int primary key auto_increment,title varchar(100) not null,content text not null,createtime timestamp default current_timestamp,updatetime timestamp default current_timestamp,uid int not null,rcount int not null default 1,`state` int default 1
)default charset 'utf8mb4';-- 創(chuàng)建視頻表
drop table if exists videoinfo;
create table videoinfo(vid int primary key,`title` varchar(250),`url` varchar(1000),createtime timestamp default current_timestamp,updatetime timestamp default current_timestamp,uid int
)default charset 'utf8mb4';-- 添加一個用戶信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES
(1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);-- 文章添加測試數(shù)據(jù)
insert into articleinfo(title,content,uid)values('Java','Java正文',1);-- 添加視頻
insert into videoinfo(vid,title,url,uid) values(1,'java title','http://www.baidu.com',1);
1.2.添加MyBatis框架依賴【新項目】
在創(chuàng)建新Spring Boot項目時,添加依賴:
在SQL中添加MyBatis Framework
和 MySQL Driver
1.3.添加MyBatis框架依賴【舊項目】
在舊項目中添加新依賴:
<!-- 添加 MyBatis 框架 -->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version>
</dependency>
<!-- 添加 MySQL 驅(qū)動 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version><scope>runtime</scope>
</dependency>
1.4.配置連接數(shù)據(jù)庫
application.yml
添加如下內(nèi)容:
spring:datasource:url: jdbc:mysql://localhost:3306/mycnblog?characterEncoding=utf8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver# 設(shè)置MyBatis
mybatis:mapper-locations:- classpath:/mybatis/*Mapper.xml#打印MyBatis 執(zhí)行SQLconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
logging:level:com.example.demo: debug
注意:如果使用mysql-connector-java是5.x之前的,使用的是“ com.mysql.jdbc.Driver ” ;如果是?于 5.x,使?的是“ com.mysql.cj.jdbc.Driver ” 。
- 有些主機&useSSL=false 會報錯,設(shè)置成true就行。
- username,password要寫自己mysql的用戶名的和密碼。
- 如果不配置,啟動項目是報錯:
1.5.配置MyBatis的XML路徑
application.yml
添加如下內(nèi)容:
# 設(shè)置MyBatis
#保存路徑 /mybatis
#保存文件后綴 名 Mapper.xml
mybatis.mapper-locations=classpath:/mybatis/*Mapper.xml
- classpath:當(dāng)前項目的根路徑
- classpath:/mybatis:當(dāng)前項目的根路徑下的文件夾叫mybatis
- *Mapper.xml:所有與mybatis相關(guān)的xml文件都叫做
某某Mapper.xml
。比如與用戶有關(guān)的叫做UserMapper.xml
。
2.MyBatis模式開發(fā)
MyBatis模式開發(fā)由兩部分組成:
Interface
:其他層可以注入使用的接口。.xml
:實現(xiàn)Interface的方法,而SQL語句就在xml文件中。
運行到MyBatis這塊,Mybatis會生成一個代理對象,代理對象會將interface的方法聲明和xml中的方法實現(xiàn)組合成代理對象的方法進行填充。實際上服務(wù)層調(diào)用MyBatis時調(diào)用的就是這個代理對象,代理對象就是一個普通類,普通類自然而然就有方法和方法實現(xiàn)。
1.新建一個mybatis文件夾:
2.添加實體類:
package com.example.demo.entity;import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;import java.time.LocalDateTime;@Data //自動添加set和get方法
public class UserInfoEntity {private Integer id;private String username;private String password;private String photo;//時間格式化@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")private LocalDateTime createTime;private LocalDateTime updateTime;
}
注意:屬性名和數(shù)據(jù)庫中的字段名保持一致,MyBatis會自動把類和數(shù)據(jù)庫中的數(shù)據(jù)關(guān)聯(lián)。
3.創(chuàng)建Mapper:
在demo下創(chuàng)建mapper包,再創(chuàng)建相應(yīng)的Interface【添加@Mapper注解】
添加接口方法,用于查詢:
package com.example.demo.mapper;import com.example.demo.entity.UserInfoEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper //注意添加注解
public interface UserMapper {List<UserInfoEntity> getAll();
}
- 沒有在xml中實現(xiàn)接口中的方法,會默認(rèn)報錯。
2.1 添加MyBatis的xml配置
<?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="com.example.demo.mapper.UserMapper"></mapper>
- namespace路徑要與當(dāng)前xml實現(xiàn)的接口路徑一致。含全包名,類名
- 在每個xxxMapper.xml中都需要添加這個xml配置!
4.在mybati文件夾下創(chuàng)建一個
xxxMapper.xml
,此處創(chuàng)建UserMapper.xml
,用于查詢用戶操作。
添加sql語句:
<select id="getAll" resultType="com.example.demo.entity.UserInfoEntity">select * from userinfo</select>
- id :當(dāng)前xml實現(xiàn)的接口中需要實現(xiàn)的方法的名字。
- resultType:返回結(jié)果,當(dāng)前xml實現(xiàn)的接口中對應(yīng)的方法返回的對象的路徑。(如果方法返回的是一個集合,只用寫集合里的對象)
5.添加Service:
咱們說,服務(wù)器是調(diào)用的,所以使用Service調(diào)用:
package com.example.demo.service;import com.example.demo.entity.UserInfoEntity;
import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public List<UserInfoEntity> getAll() {return userMapper.getAll();}
}
- 注入 uerMapper:MyBatis允許使用Interface,因為最終實現(xiàn)這行的是由代理對象來填充的。
- Service層調(diào)用,然后使用xml文件來實現(xiàn)Interface里的方法具體實現(xiàn)。
6.添加Controller:
package com.example.demo.controller;import com.example.demo.entity.UserInfoEntity;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/user")
public class UserController {@AutowiredUserService userService;@RequestMapping("/getAll")public List<UserInfoEntity> getAll(){return userService.getAll();}
}
7.運行項目,輸入url地址
3.增查改刪(CRUD)
?戶的增加、刪除和修改的操作,對應(yīng)使? MyBatis 的標(biāo)簽如下:
- < insert>標(biāo)簽:插?語句
- < update>標(biāo)簽:修改語句
- < delete>標(biāo)簽:刪除語句
5.1.增加操作
mapper 接口方法 實現(xiàn)代碼:
int add(@Param("username") String username,@Param("password") String password);
xml的sql語句具體實現(xiàn):
默認(rèn)情況下返回的是受影響的?號。
<insert id="add">insert into userinfo(username,password)value(#{username},#{password})
</insert>
- #{}是替換符。
service代碼:
public int add(@Param("username") String username, @Param("password") String password){return userMapper.add(username,password);
}
controller代碼:
@RequestMapping("/add")
public int add(@Param("username") String username, @Param("password") String password){return userService.add(username,password);
}
重新運行項目,輸入url,輸入?yún)?shù):
查詢數(shù)據(jù)庫,看是否添加成功:
5.2.修改操作
因為除了controller里的代碼和sql語句會有些不同,其余層代碼基本一致【照著增加操作模仿】,所以以下只寫controller代碼和SQL語句:
Controller代碼:
@RequestMapping("/update")
public int update(@Param("id")Integer id,@Param("username") String username){return userService.update(id,username);
}
XML中的SQL語句:
<update id="update">update userinfo set username=#{username} where id=#{id}
</update>
運行結(jié)果:
5.3 刪除操作
其他代碼雷同,SQL語句:
<delete id="delById">delete from userinfo where id=#{id}
</delete>
6.查詢操作
6.1單表查詢
實現(xiàn)根據(jù)用戶id查詢用戶信息的功能:
Controller代碼如下:
@RequestMapping("/getuser")
public UserInfoEntity getUserById(Integer id) {return userService.getUserById(id);
}
XML的SQL語句實現(xiàn)如下:
<select id="getUserById" resultType="com.example.demo.entity.UserInfoEntity">select * from userinfo where id=#{id}
</select>
6.2 參數(shù)占位符 #{} 與 ${} 區(qū)別
在MyBatis中,#{}
和 ${}
是參數(shù)占位符,用于在SQL語句中插入?yún)?shù)值。它們的主要區(qū)別在于如何處理參數(shù)。
-
#{}
預(yù)編譯處理:-
MyBatis 在處理#{}時,會將 SQL 中的 #{} 替換為?號,使? PreparedStatement
的 set ?法來賦值。
-
使用
#{}
時,MyBatis會將參數(shù)值作為預(yù)編譯的參數(shù)進行處理,可以有效防止SQL注入攻擊。 -
#{}
會自動進行參數(shù)類型轉(zhuǎn)換和安全處理,使得傳遞參數(shù)更加方便和安全。 -
#{}
可以直接在SQL語句中使用,例如WHERE column_name = #{paramName}
。
-
-
${}
直接替換處理:- MyBatis 在處理 ${} 時,就是把 ${} 簡單的替換成變量的值,不做任何的特殊處理,比如
${}
不會自動添加''
號,而#{}
會自動加上''
號。 - 使用
${}
時,MyBatis會將參數(shù)值直接拼接到SQL語句中,類似于字符串替換。 ${}
不會對參數(shù)進行安全處理或類型轉(zhuǎn)換,可能存在SQL注入風(fēng)險。${}
可以用于動態(tài)生成SQL語句的部分內(nèi)容,例如表名、列名等。
- MyBatis 在處理 ${} 時,就是把 ${} 簡單的替換成變量的值,不做任何的特殊處理,比如
綜上所述,#{}
和 ${}
的區(qū)別主要在于參數(shù)的處理方式和安全性:
#{}
是推薦的使用方式,能夠提供更好的安全性和可讀性,并且支持參數(shù)類型轉(zhuǎn)換。${}
可以用于一些特殊場景,例如動態(tài)生成SQL語句的部分內(nèi)容,但需要注意潛在的SQL注入問題。
在編寫MyBatis的SQL語句時,請根據(jù)具體需求選擇合適的參數(shù)占位符,以確保代碼的安全和穩(wěn)定性。
請注意,有些特殊情況下(例如在動態(tài)SQL中),可能需要結(jié)合使用 #{}
和 ${}
來實現(xiàn)更靈活的功能。
6.2.1.SQL注入問題
SQL注入是一種常見的安全漏洞,攻擊者可以在應(yīng)用程序中的輸入點插入惡意的SQL代碼來執(zhí)行未經(jīng)授權(quán)的操作或獲取敏感數(shù)據(jù)。以下是一個簡單的SQL注入示例:
假設(shè)有一個簡單的登錄功能,用戶可以通過輸入用戶名和密碼進行身份驗證:
@RequestMapping("/islogin")
public UserInfoEntity isLogin(String username,String password){return userService.isLogin(username,password);
}
XML代碼:
<select id="isLogin" resultType="com.example.demo.entity.UserInfoEntity">select * from userinfo where username='${username}' and password='${password}'
</select>
在上述代碼中,使用直接替換的方式將用戶輸入內(nèi)容直接替換到SQL查詢語句中。如果攻擊者在用戶名或密碼輸入框中輸入惡意的值,就可以構(gòu)造出惡意的SQL語句,例如:
localhost:8080/user/islogin?username=lisi&password='or 1=1 and id = '5
假設(shè)MySQL的userinfo表如下:
使用postman演示:
最終構(gòu)成的代碼是:
SELECT * FROM userinfo WHERE username = 'lisi' AND password = ''or 1=1 and id = '5'
- 上述sql語句表示,查詢userinfo表,username是lisi, 并且 password為空;或者 1=1 并且id=5。username=’lisi‘為真,password是空為假,但是1=1and id=5 為真,于是不需要密碼就查詢到了結(jié)果。
這個惡意的SQL語句繞過了正常的身份驗證邏輯,使得查詢條件始終為真,因此可以繞過登錄功能并返回所有用戶的數(shù)據(jù)。要防止SQL注入攻擊,可以使用參數(shù)化查詢(使用#{}
參數(shù)占位符)或預(yù)編譯語句來構(gòu)建SQL語句。
6.2.2 like查詢
簡單使用#{} 進行l(wèi)ike查詢會無結(jié)果的:
<select id="findUserByName" resultType="com.example.demo.entity.UserInfoEntity">select * from userinfo where username like '%#{username}%'</select>
在上述示例中,#{username}
是占位符,%
是通配符。如果傳遞username值為“l(fā)isi”相當(dāng)于:select * from userinfo where username like '%'lisi'%';
是查詢不到結(jié)果的。
進行l(wèi)ike查詢,需要使用#{},加上配合mysql內(nèi)置函數(shù) concat()
來實現(xiàn):
<select id="findUserByName" resultType="com.example.demo.entity.UserInfoEntity">select * from userinfo where username like concat('%',#{usernam
e});
</select>
在上述示例中,#{username}
是占位符,可以通過參數(shù)傳遞具體的值。使用CONCAT()
函數(shù)將占位符和%
通配符連接在一起,實現(xiàn)以指定值開頭的模糊匹配。
6.2.3 屬性名和字段名不一致
如果是增、刪、改返回受影響的?數(shù),那么在 mapper.xml 中是可以不設(shè)置返回的類型的,因為默認(rèn)是返回受影響的行數(shù),如下圖所示:
但是,查詢操作不設(shè)置返回類型,則會報錯:
<select id="getById" >select * from userinfo where id=#{id}</select>
運行結(jié)果:
顯示運行了一個查詢但沒有找到結(jié)果映射,也就是說對于< select >
查詢標(biāo)簽至少需要兩個屬性:
- id屬性:用于標(biāo)識實現(xiàn)接口中的某個方法;
- 結(jié)果映射屬性:有兩種實現(xiàn)標(biāo)簽
< resultMap>
與< resultType>
6.3 resultType
大多數(shù)情況下都可以使用resultType
,原因是使用方便,直接定義到某個實體類的路徑就行;
<select id="getAll" resultType="com.example.demo.entity.UserInfoEntity">select * from userinfo</select>
表示將查詢結(jié)果映射到UserInfoEntity
對象。
6.3.1 resultMap
resultMap使用場景:
- 字段名和程序中屬性名不一致,可使用resultMap配置映射。
- 一對一和一對多關(guān)系,可以使用resultMap映射并查詢數(shù)據(jù)。
<resultMap id="userResultMap" type="com.example.User"><id property="id" column="user_id"></id><result property="username" column="user_name"><]</result><result property="email" column="user_email"></result>><!-- 其他映射關(guān)系 --><!-- ..... --></resultMap><select id="getAll" resultMap="userResultMap">select * from userinfo
</select>
在上述示例中,<resultMap>
定義了User
類與查詢結(jié)果的映射關(guān)系。具體解釋如下:
property
屬性:property
屬性指定Java對象屬性的名稱。column
屬性:column
屬性指定數(shù)據(jù)庫表中對應(yīng)字段的列名。id
屬性:主鍵- result屬性:普通字段和屬性
通過配置合適的<resultMap>
,可以靈活地定義不同查詢的映射關(guān)系,以滿足特定業(yè)務(wù)需求。
使用時,只需要將ResultMap配置的id名,添加到相應(yīng)的位置,如上述代碼中< select >
標(biāo)簽
java類屬性如下:
數(shù)據(jù)庫字段如下:
雖然屬性和字段名不一致,但通過上述resultMap配置后,一樣可以成功映射:
6.3.2 多表查詢
ArticleInfo類:
package com.example.demo.entity;import lombok.Data;import java.time.LocalDateTime;@Data
public class ArticleInfo {private int id;private String title;private String content;private LocalDateTime createtime;private LocalDateTime updatatime;private int uid;@Overridepublic String toString() {return "ArticleInfo{" +"id=" + id +", title='" + title + '\'' +", content='" + content + '\'' +", createtime=" + createtime +", updatatime=" + updatatime +", uid=" + uid +'}';}
}
ArticleInfoVO類:
package com.example.demo.entity.vo;import com.example.demo.entity.ArticleInfo;
import lombok.Data;@Data
public class ArticleInfoVO extends ArticleInfo {private String username;@Overridepublic String toString() {return "ArticleInfoVO{" +"username='" + username + '\'' +"} " + super.toString();}
}
ArticleMapper:
package com.example.demo.mapper;import com.example.demo.entity.vo.ArticleInfoVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;@Mapper
public interface ArticleMapper {//查詢文章詳情ArticleInfoVO getDetail(@Param("id")Integer id);
}
XML:重點還是sql語句
<?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="com.example.demo.mapper.ArticleMapper"><select id="getDetail" resultType="com.example.demo.entity.vo.ArticleInfoVO">select a.*,u.username from articleinfo aleft join userinfo u on u.id=a.uidwhere a.id=#{id}</select>
</mapper>
Test測試類:
這是一個單元測試的類:
package com.example.demo.mapper;import com.example.demo.entity.vo.ArticleInfoVO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
class ArticleMapperTest {@Autowiredprivate ArticleMapper articleMapper;@Testvoid getDetail() {ArticleInfoVO articleInfoVO = articleMapper.getDetail(2);System.out.println(articleInfoVO);}
}
測試類運行結(jié)果:
7.動態(tài)SQL
MyBatis提供了強大的動態(tài)SQL功能,可以根據(jù)不同的條件來動態(tài)生成SQL語句。大白話就是允許我們在xml進行條件判斷。
【mybatis】
7.1 < if >標(biāo)簽
假設(shè)在注冊一個賬號時,需要輸入賬戶和密碼【必填字段】,而性別可以選擇性填寫【非必填字段】,那么如果有不確定的字段傳入,這個時候就需要使用動態(tài)標(biāo)簽< if >
來判斷了,比如性別sex可為非必填字段,具體實現(xiàn)如下:
<insert id="add">insert into userinfovalue(#{username},#{password},<if test="sex != null">sex = #{sex},</if>#{age})</insert>
在上述示例中,<if>
標(biāo)簽被嵌套在<inser>
語句內(nèi)部。<if>
標(biāo)簽中的test
屬性指定了條件表達(dá)式,test
中傳入的是對象屬性,滿足條件時才會包含對應(yīng)的SQL代碼。
在示例中,如果傳入的userinfo
對象的sex
屬性不為空,則生成一個sex = #{sex},
的條件;這樣就可以根據(jù)不同情況拼接不同的查詢條件。
<if>
標(biāo)簽還支持更復(fù)雜的條件判斷,可以使用比較運算符、邏輯運算符、調(diào)用對象方法等。
需要注意的是,在使用<if>
時需要遵循以下幾點:
- 條件表達(dá)式必須是合法的OGNL表達(dá)式。
- 在條件表達(dá)式中使用
null
時,要使用" != null"進行判斷,不能直接使用"=="。 - 條件表達(dá)式中的字符串比較要注意處理空字符串,比如
<if test="name != null and name != ''">
。
7.2 < trim >標(biāo)簽
<trim>
標(biāo)簽是用于處理SQL語句中多余的空格和逗號的XML元素。它可以根據(jù)需要添加或移除SQL語句中的前綴、后綴、前后綴或者連接詞。
<trim>
標(biāo)簽有以下屬性可用:
prefix
:在SQL語句開頭添加的前綴。prefixOverrides
:需要移除的前綴內(nèi)容。suffix
:在SQL語句末尾添加的后綴。suffixOverrides
:需要移除的后綴內(nèi)容。
下面是一個使用<trim>
標(biāo)簽的示例:
<select id="getUserList" parameterType="com.example.User" resultType="com.example.User">SELECT * FROM usersWHERE id =#{id} and <trim prefix="AND" prefixOverrides="OR"><if test="name != null and name != ''">OR name = #{name}</if><if test="age != null">OR age = #{age}</if></trim>
</select>
在上述示例中,<trim>
標(biāo)簽被嵌套在<where>
語句內(nèi)部。<trim>
標(biāo)簽根據(jù)指定的條件添加或移除相應(yīng)的前綴和前綴內(nèi)容。
在示例中,如果傳入的User
對象的name
屬性不為空,則生成一個前綴為"AND"的條件,并移除前綴中多余的"OR",也就是AND name = #{name}
;如果age
屬性不為空,則生成一個前綴為"AND"的條件,并移除前綴中多余的"OR",也就是AND age = #{age}
。這樣可以動態(tài)地拼接多個條件。當(dāng)然也可以拼,
號;(
號、)
號。
比如:
<insert id="add">insert into user
<trim prefix="(" suffix=")" suffixOverrides=","><if test="username != null">username,</if><if test="password != null">password,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="username != null">#{username},</if><if test="password != null">#{password},</if></trim>
</insert>
上述代碼:在第一個< trim>
標(biāo)簽,在語句開始部分會加上(
,如果傳入的username
不為空,則會生成一個username
并把,
去掉,如果傳入的password
不為空,則會生成一個password
并把,
去掉,最后加上)
;
在第二個< trim>
標(biāo)簽,在語句開始部分會加上values (
,如果傳入的username
不為空,則會生成一個username
并把,
去掉,如果傳入的password
不為空,則會生成一個password
并把,
去掉,最后加上)
;
7.3 < where >標(biāo)簽
<where>
標(biāo)簽是用于動態(tài)生成SQL語句中的WHERE
。它可以根據(jù)條件判斷自動生成和連接各個查詢條件,并且能夠處理多余的邏輯運算符(如AND
、OR
)。
下面是一個使用<where>
標(biāo)簽的示例:
<select id="getUserList" parameterType="com.example.User" resultType="com.example.User">SELECT * FROM users<where><if test="name != null and name != ''">AND name = #{name}</if><if test="age != null">AND age = #{age}</if></where>
</select>
在上述示例中,<where>
標(biāo)簽包含了兩個<if>
標(biāo)簽,每個<if>
標(biāo)簽表示一個查詢條件。當(dāng)條件滿足時,該條件會被添加到WHERE
子句中。
如果傳入的User
對象的name
屬性不為空,則生成一個條件 name = #{name}
,會自動把多余的AND
去掉;如果age
屬性不為空,則生成一個條件AND age = #{age}
,此處的AND
是有效的,就不會去掉了。
-
使用
<where>
標(biāo)簽?zāi)軌騽討B(tài)生成合理的WHERE
子句,避免因為沒有查詢條件而導(dǎo)致的無效或錯誤的SQL語句。 -
需要注意的是,
<where>
標(biāo)簽會自動處理多余的邏輯運算符,例如只有一個條件時,生成的SQL語句不會包含前置的AND
。
7.4 < set >標(biāo)簽
<set>
標(biāo)簽是用于動態(tài)生成UPDATE
語句中SET
子句的XML元素。它可以根據(jù)條件判斷自動生成要更新的字段和對應(yīng)的值,并且能夠處理多余的逗號(,
)。
下面是一個使用<set>
標(biāo)簽的示例:
<update id="updateUser" parameterType="com.example.User">UPDATE users<set><if test="name != null and name != ''">name = #{name},</if><if test="age != null">age = #{age},</if></set>WHERE id = #{id}
</update>
在上述示例中,<set>
標(biāo)簽包含了兩個<if>
標(biāo)簽,每個<if>
標(biāo)簽表示一個要更新的字段和對應(yīng)的值。再次強調(diào)test
傳入的就是對象屬性;當(dāng)條件滿足時,該字段和值會被添加到SET子句中。
如果傳入的User
對象的name
屬性不為空,則生成一條更新語句name = #{name},
;如果age
屬性不為空,則生成一條更新語句age = #{age},
,并會自動的去掉最后一個逗號(,
)。
-
使用
<set>
標(biāo)簽?zāi)軌騽討B(tài)生成合理的SET子句,避免因為沒有更新字段而導(dǎo)致的無效或錯誤的SQL語句。同時,<set>
標(biāo)簽會自動處理多余的逗號,確保生成的UPDATE語句的語法正確。 -
需要注意的是,在編寫UPDATE語句時,
<set>
標(biāo)簽應(yīng)該位于WHERE子句之前。
7.5 < foreach >標(biāo)簽
<foreach>
標(biāo)簽是用于在SQL語句中循環(huán)遍歷集合或數(shù)組的XML元素。它可以方便地將集合或數(shù)組中的元素插入到SQL語句中,生成批量操作的語句。
對集合進?遍歷時可以使?該標(biāo)簽。< foreach >標(biāo)簽有如下屬性:
-
collection:指定要遍歷的集合或數(shù)組,如 List,Set,Map或數(shù)組對象
-
item:指定在每次迭代中將集合或數(shù)組的元素賦值給的變量名。
-
index:指定在每次循環(huán)迭代中,集合中的當(dāng)前索引將被賦值給的變量。
-
open:語句塊開頭的字符串
-
close:語句塊結(jié)束的字符串
-
separator:指定每個循環(huán)迭代之間的分隔符。
下面是一個使用<foreach>
標(biāo)簽的示例:
<insert id="addList">INSERT INTO users (name, age) VALUES<foreach collection="list" item="user" separator=",">(#{user.name}, #{user.age})</foreach>
</insert>
在上述示例中,<foreach>
標(biāo)簽是在INSERT語句中遍歷List
類型的參數(shù)list
。每次迭代都將取出集合中的元素賦值給user
變量,然后將該元素的屬性name
和age
插入到VALUES子句中。
-
通過使用
<foreach>
標(biāo)簽,可以輕松實現(xiàn)對集合或數(shù)組進行批量操作,如批量插入、批量更新等。 -
需要注意的是,
<foreach>
標(biāo)簽也支持一些其他屬性,例如index
屬性表示當(dāng)前迭代的索引位置,open
和close
屬性用于定義在循環(huán)的開頭和結(jié)尾添加的字符串。
以下是一個使用open
和close
屬性的示例:
<select id="getUsersByIdList" parameterType="java.util.List" resultType="com.example.User">SELECT * FROM usersWHERE id IN<foreach collection="list" item="id" open="(" close=")" separator=",">#{id}</foreach>
</select>
open
屬性定義了循環(huán)的開頭字符串,它會在整個循環(huán)的最前面被插入。一般情況下,我們可以將它用來添加開始的括號、引號等。如果不需要在開頭添加任何字符串,可以將open
屬性設(shè)置為空字符串或省略不寫。
在上述示例中,我們想要查詢一組用戶的信息,這組用戶的ID存儲在一個List
類型的參數(shù) list
中。通過使用<foreach>
標(biāo)簽,我們將每個ID作為查詢條件的一部分,將它們以逗號分隔放在括號內(nèi)。
假設(shè)list
中包含了三個ID,那么生成的SQL語句將類似于:
SELECT * FROM users WHERE id IN (1, 2, 3);
通過在<foreach>
標(biāo)簽中使用open
和close
屬性,我們可以方便地添加括號使查詢條件得到正確的語法結(jié)構(gòu)。