一、數據傳遞
返回值為:字符串
package com.apesource.springboot_web_04.controller;import com.apesource.springboot_web_04.pojo.Emp;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;/*** 返回值為:字符串*/
@Controller
@RequestMapping("/string")
public class StringController_01 {/*** 進入首頁**/@RequestMapping("/show")public String show(){return "index";}
}
package com.apesource.springboot_web_04.controller;import com.apesource.springboot_web_04.pojo.Emp;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.ArrayList;
import java.util.List;
import java.util.Map;@Controller
@RequestMapping("/json")
public class JsonController_02 {/*** @ResponseBody 對象===>json* 位置:1.類* 2.方法** @RequestBody json===>對象* 位置:方法參數** @RestController = @Controller + @ResponseBody*/@RequestMapping("/show1")@ResponseBodypublic List<Emp> show1(){//1.模擬數據庫Emp emp1=new Emp(1,"張毅老師","男");Emp emp2=new Emp(2,"張毅老師","男");Emp emp3=new Emp(3,"張毅老師","男");List<Emp> list=new ArrayList<>();list.add(emp1);list.add(emp2);list.add(emp3);return list;}@RequestMapping("/show2")@ResponseBodypublic String show2(){return "helloWorld";}
}
二、文件上傳
1.添加坐標
<!--文件上傳--><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.3</version></dependency>
2.UserController
package com.apesource.springboot_web_04.controller;import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletRequest;
import java.io.IOException;@Controller
@RequestMapping("/for")
public class UserController {//進入測試頁面@RequestMapping("/show")public String show(){return "index";}//文件上傳@RequestMapping("/fileupload")public String fileupload(String uname, MultipartFile upic, HttpServletRequest request){System.out.println("用戶名:"+uname);System.out.println(upic);System.out.println(upic.getOriginalFilename());System.out.println(upic.getName());//方式1.將文件upic以流的方式寫入當前服務器磁盤(應用服務器)//方式2.文件服務器(七牛云)//構造一個帶指定 Region 對象的配置類Configuration cfg = new Configuration(Region.autoRegion());//...其他參數參考類注釋UploadManager uploadManager = new UploadManager(cfg);//...生成上傳憑證,然后準備上傳String accessKey = "Tfv6J4DIRakNREBeGc8eNL21xEAP2uXsyvUa8esk";String secretKey = "Dr5lD7XypDenJ6i14DtqxKK87dkA9ux47xn53tUB";String bucket = "2025ks";//默認不指定key的情況下,以文件內容的hash值作為文件名String key = null;try {byte[] uploadBytes = upic.getBytes();Auth auth = Auth.create(accessKey, secretKey);String upToken = auth.uploadToken(bucket);try {Response response = uploadManager.put(uploadBytes, key, upToken);//解析上傳成功的結果DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);System.out.println(putRet.key);//獲取文件名System.out.println(putRet.hash);//獲取文件hash值} catch (QiniuException ex) {Response r = ex.response;System.err.println(r.toString());try {System.err.println(r.bodyString());} catch (QiniuException ex2) {//ignore}}} catch (Exception ex) {//ignore}return "success";}}
3.index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>文件上傳</title>
</head>
<body>文件上傳:<ol><li>坐標</li><li>制作頁面-form表單編碼</li><li>通過*****接受文件</li></ol><hr/><form action="fileupload" method="post" enctype="multipart/form-data">用戶名:<input name="uname"/><br/>圖片:<input name="upic" type="file"/><br/><input type="submit" value="上傳"/></form></body>
</html>
4.success.html?
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>文件上傳</title>
</head>
<body>成功頁面
</body>
</html>
三、注冊Servlet、Filter、Listener
而由于 Spring Boot 默認是以 jar 包的方式運行嵌入式Servlet容器來啟動應用,沒有web.xml文件,
Spring提供以下Bean來注冊三大組件
ServletRegistrationBean? 注冊自定義Servlet
FilterRegistrationBean? 注冊自定義Filter
ServletListenerRegistrationBean 注冊自定義Listener
第一種:
package com.apesource.springboot_web_04.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet(urlPatterns = "/myServlet")
public class MyServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("進入servlet");resp.getWriter().println("<h1>hello world</h1>");};@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req,resp);}
}
@ServletComponentScan包掃描?(入口類)
@ServletComponentScan
@SpringBootApplication
public class SpringbootWeb04Application {public static void main(String[] args) {SpringApplication.run(SpringbootWeb04Application.class, args);}}
第二種::配置類
package com.apesource.springboot_web_04.config;import com.apesource.springboot_web_04.servlet.MyServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.Arrays;@Configuration
public class MyMvcConfig {//注冊替換Servlet//替換:@WebServlet(urlPatterns="/myServlet")@Beanpublic ServletRegistrationBean doServlet(){ServletRegistrationBean<MyServlet> bean=new ServletRegistrationBean<MyServlet>();bean.setServlet(new MyServlet());bean.setUrlMappings(Arrays.asList("/myServlet"));return bean;}
}
四、切換為其他嵌入式Servlet容器
SpringBoot 默認針對Servlet容器提供以下支持:
Tomcat(默認使用)
Jetty :支持長連接項目(如:聊天頁面)
Undertow : 不支持 JSP , 但是并發性能高,是高性能非阻塞的容器
默認Tomcat服務器
在spring-boot-starter-web啟動器中默認引入了tomcat容器
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><version>2.1.0.RELEASE</version><scope>compile</scope>
</dependency>
切換 Jetty 容器
dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><!-- 排除tomcat容器 --><exclusions><exclusion><artifactId>spring-boot-starter-tomcat</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions>
</dependency>
<!--引入其他的Servlet容器-->
<dependency><artifactId>spring-boot-starter-jetty</artifactId><groupId>org.springframework.boot</groupId>
</dependency>
Servlet容器:運行啟動類就可啟動,或將項目打成可執行的 jar 包
優點:簡單、快捷;
缺點:默認不支持JSP、優化定制比較復雜使用定制器, 還需要知道 每個功能 的底層原理
外置Servlet容器:配置 Tomcat, 將項目部署到Tomcat中運行
五、restFul
滿足這些約束條件和原則的應用程序或設計就是 RESTful。
設計RESTful風格的API:
1、在RESTful風格的架構中, 每個網址代表一種資源,所以網址中不能有動詞,只能有名詞。而且所
用的名詞往往與數據庫的表名對應。
2、HTTP動詞設計: GET (獲取資源) POST (新建資源) PUT (更新資源,客戶端提供改變后的完整資源)? ?DELETE (刪除資源)
請求方式
含義
GET /zoos? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?列出所有動物園
POST /zoos? ? ? ? ? ? ? ? ? ? ? ? ? ? 新建一個動物園
GET /zoos/ID? ? ? ? ? ? ? ? ? ? ? ? ? 獲取某個指定動物園的信息
PUT /zoos/ID? ? ? ? ? ? ? ? ? ? ? ? ? 更新某個指定動物園的信息(提供該動物園的全部信息)
DELETE /zoos? ? ? ? ? ? ? ? ? ? ? ? ?刪除某個動物園
GET /zoos/lD/animals? ? ? ? ? ? ? 列出某個指定動物園的所有動物
DELETE /zoos/lD/animals/ID? ?刪除某個指定動物園的指定動物
六、springboot與mybtais及mybatis-plus整合
MyBatisPlus的入門案例與簡介,這個和其他課程都不太一樣,其他的課程都是先介紹概念,然后再寫入門案例。而對于MyBatisPlus的學習,我們將順序做了+調整,主要的原因MyBatisPlus主要是對? MyBatis的簡化,所有我們先體會下它簡化在哪,然后再學習它是什么,以及它幫我們都做哪些事。
MybatisPlus(簡稱MP)是基于MyBatis框架基礎上開發的增強型工具,旨在簡化開發、提供效率。
開發方式
基于SpringBoot使用MyBatisPlus
步驟1:創建數據庫及表
create database if not exists mybatisplus_db character set utf8;
use mybatisplus_db;
CREATE TABLE user (id bigint(20) primary key auto_increment,name varchar(32) not null,password ?varchar(32) not null,age int(3) not null ,tel varchar(32) not null
);
insert into user values(1,'Tom','tom',18,'13991267980');
insert into user values(2,'Jerry','jerry',18,'13991267980');
insert into user values(3,'Jock','Jock',18,'13991267980');
步驟2:創建SpringBoot工程
步驟3:勾選配置使用技術
說明:? ? 由于MP并未被收錄到idea的系統內置配置,無法直接選擇加入,需要手動在pom.xml中配置添加
步驟4:pom.xml補全依賴
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.16</version>
</dependency>
步驟5:添加MP的相關配置信息
spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=GMTusername: rootpassword: 132456
步驟6:根據數據庫表創建實體類
public class User { ? private Long id;private String name;private String password;private Integer age;private String tel;//setter...getter...toString方法略
}
步驟7:創建Dao接口
@Mapper
public interface UserDao extends BaseMapper<User>{
}
步驟8:編寫引導類
@SpringBootApplication
public class Mybatisplus01QuickstartApplication {public static void main(String[] args) {SpringApplication.run(Mybatisplus01QuickstartApplication.class, args);}
}
說明:Dao接口要想被容器掃描到,有兩種解決方案:
方案一:在Dao接口上添加@Mapper注解,并且確保Dao處在引導類所在包或其子包中
該方案的缺點是需要在每一Dao接口中添加注解
方案二:在引導類上添加@MapperScan注解,其屬性為所要掃描的Dao所在包
該方案的好處是只需要寫一次,則指定包下的所有Dao接口都能被掃描到,@Mapper就可以
不寫。
步驟9:編寫測試類
@SpringBootTest
class MpDemoApplicationTests {@Autowiredprivate UserDao userDao;@Testpublic void testGetAll() {List<User> userList = userDao.selectList(null);System.out.println(userList);}
}
分頁功能
分頁查詢使用的方法是:
IPage<T> selectPage(IPage<T> page, Wrapper<T> queryWrapper)
IPage:用來構建分頁查詢條件
Wrapper:用來構建條件查詢的條件,目前我們沒有可直接傳為Null
IPage:返回值,你會發現構建分頁條件和方法的返回值都是IPage
IPage是一個接口,我們需要找到它的實現類來構建它,具體的實現類,可以進入到IPage類中按ctrl+h,? 會找到其有一個實現類為Page。
步驟1:調用方法傳入參數獲取返回值
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {@Autowiredprivate UserDao userDao;//分頁查詢@Testvoid testSelectPage(){//1 創建IPage分頁對象,設置分頁參數,1為當前頁碼,3為每頁顯示的記錄數
步驟2:設置分頁攔截器 這個攔截器MP已經為我們提供好了,我們只需要將其配置成Spring管理的bean對象即可。
步驟3:運行測試程序 如果想查看MP執行的SQL語句,可以修改application.yml配置文件,三.DQL編程控制 增刪改查四個操作中,查詢是非常重要的也是非常復雜的操作,這塊需要我們重點學習下,這節我們主
要學習的內容有:
條件查詢方式
查詢投影
查詢條件設定
字段映射與表名映射IPage<User> page=new Page<>(1,3);//2 執行分頁查詢userDao.selectPage(page,null);//3 獲取分頁結果System.out.println("當前頁碼值:"+page.getCurrent());System.out.println("每頁顯示數:"+page.getSize());System.out.println("一共多少頁:"+page.getPages());System.out.println("一共多少條數據:"+page.getTotal());System.out.println("數據:"+page.getRecords());}
}
步驟2:設置分頁攔截器? ?
這個攔截器MP已經為我們提供好了,我們只需要將其配置成Spring管理的bean對象即可。
@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){//1 創建MybatisPlusInterceptor攔截器對象MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();//2 添加分頁攔截器mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());return mpInterceptor;}
}
步驟3:運行測試程序
如果想查看MP執行的SQL語句,可以修改application.yml配置文件,
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印SQL日志到控制臺
DQL編程控制
增刪改查四個操作中,查詢是非常重要的也是非常復雜的操作,這塊需要我們重點學習下,這節我們主要學習的內容有:
條件查詢方式
查詢投影
查詢條件設定
字段映射與表名映射
條件查詢
1.構建條件查詢
在進行查詢的時候,我們的入口是在Wrapper這個類上,因為它是一個接口,所以我們需要去找它對應的實現類,關于實現類也有很多,說明我們有多種構建查詢條件對象的方式,
先來看第一種:QueryWrapper?
/*** QueryWrapper的lt小于()方法* 查詢年齡小于19的*/@Testvoid testGetAll(){QueryWrapper qw=new QueryWrapper();qw.lt("age",19);List<User> userlist = userMapper.selectList(qw);System.out.println(userlist);}
lt: 小于(<) ,最終的sql語句為? ?select??id,name,password,age,tel FROM user WHERE (age < ?)
接著來看第二種:LambdaQueryWrapper
/*** LambdaQueryWrapper的lt小于()方法* 查詢年齡小于19的*/@Testvoid testGetAll2(){LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<User>();lqw.lt(User::getAge,19);List<User> users = userMapper.selectList(lqw);System.out.println(users);}
多條件構建
需求:查詢數據庫表中,年齡在10歲到30歲之間的用戶信息
/*** ,年齡在10歲到30歲之間的用戶信息* gt:大于(>)*/@Testvoid testGetAll3(){LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<User>();lqw.lt(User::getAge,30);lqw.gt(User::getAge,10);List<User> users = userMapper.selectList(lqw);System.out.println(users);}
gt:大于(>),最終的SQL語句為:SELECT id,name,password,age,tel FROM user WHERE (age < ? AND age > ?)
構建多條件的時候,可以支持鏈式編程
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, 30).gt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
查詢數據庫表中,年齡小于10或年齡大于30的數據
/*** 年齡小于10或年齡大于30的* or()就相當于我們sql語句中的or關鍵字,不加默認是and,* 、構建多條件的時候,可以支持鏈式編程*/@Testvoid testGetAll4(){LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<User>();lqw.lt(User::getAge,10).or().gt(User::getAge,30);List<User> users = userMapper.selectList(lqw);System.out.println(users);}
or()就相當于我們sql語句中的or關鍵字,不加默認是and,最終的sql語句為:
SELECT id,name,password,age,tel FROM user WHERE (age < ? OR age > ?)
null判定?
需求:查詢數據庫表中,根據輸入年齡范圍來查詢符合條件的記錄
用戶在輸入值的時候,
如果只輸入第一個框,說明要查詢大于該年齡的用戶
如果只輸入第二個框,說明要查詢小于該年齡的用戶
如果兩個框都輸入了,說明要查詢年齡在兩個范圍之間的用戶
我們可以使用兩個簡單數據類型,也可以使用一個模型類,但是User類中目前只有一個age屬性
新建一個模型類,讓其繼承User類,并在其中添加age2屬性,UserQuery在擁有User屬性后同時添加了age2屬性。
@Data
public class User {private Long id;private String name;private String password;private Integer age;private String tel;
}
@Data
public class UserQuery extends User {private Integer age2;
}
@Testvoid testGetAll(){//模擬頁面傳遞過來的查詢數據UserQuery uq = new UserQuery();uq.setAge(10);uq.setAge2(30);LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();if(null != uq.getAge2()){lqw.lt(User::getAge, uq.getAge2());}if( null != uq.getAge()) {lqw.gt(User::getAge, uq.getAge());}List<User> userList = userDao.selectList(lqw);System.out.println(userList);
上面的寫法可以完成條件為非空的判斷,但是問題很明顯,如果條件多的話,每個條件都需要判斷,代碼量就比較大,來看MP給我們提供的簡化方式:
?@Testvoid testGetAll(){//模擬頁面傳遞過來的查詢數據UserQuery uq = new UserQuery();uq.setAge(10);uq.setAge2(30);LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();lqw.lt(null!=uq.getAge2(),User::getAge, uq.getAge2());lqw.gt(null!=uq.getAge(),User::getAge, uq.getAge());List<User> userList = userDao.selectList(lqw);System.out.println(userList);}
查詢投影
目前我們在查詢數據的時候,什么都沒有做默認就是查詢表中所有字段的內容,我們所說的查詢投影即不查詢所有字段,只查詢出指定內容的數據。
@Testvoid testGetAll7(){LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<User>();lqw.select(User::getId,User::getName,User::getAge);List<User> users = userMapper.selectList(lqw);System.out.println(users);}
// 如果使用的不是lambda,就需要手動指定字段@Testvoid testGetAll8(){QueryWrapper<User> lqw=new QueryWrapper<User>();lqw.select("id","name","age","tel");List<User> users = userMapper.selectList(lqw);System.out.println(users);}
聚合查詢
需求:聚合函數查詢,完成count、max、min、avg、sum的使用
count:總記錄數
max:最大值
min:最小值
avg:平均值
sum:求和
//聚合查詢@Testvoid testGetAll9(){QueryWrapper<User> lqw=new QueryWrapper<User>();
// lqw.select("count(*) as count");
// lqw.select("max(age) as maxAge");
// lqw.select("min(age) as minAge");
// lqw.select("sum(age) as sumAge");lqw.select("avg(age) as avgAge");List<Map<String, Object>> maps = userMapper.selectMaps(lqw);System.out.println(maps);}
分組查詢
需求:分組查詢,完成 group by的查詢使用
//分組查詢@Testvoid testGetAll10(){QueryWrapper<User> lqw=new QueryWrapper<User>();lqw.select("count(*) as count,tel");lqw.groupBy("tel");List<Map<String, Object>> maps = userMapper.selectMaps(lqw);System.out.println(maps);}
注意:聚合與分組查詢,無法使用lambda表達式來完成
查詢條件
前面我們只使用了lt()和gt(),除了這兩個方法外,MP還封裝了很多條件對應的方法,這一節我們重點把
MP提供的查詢條件方法進行學習下。
MP的查詢條件有很多:
范圍匹配(> 、 = 、between)
模糊匹配(like)
空判定(null)
包含性匹配(in)
分組(group)
排序(order)
......
1.等值查詢
需求:根據用戶名和密碼查詢用戶信息
@Testvoid testGetAll11(){LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<User>();lqw.eq(User::getName,"Jerry").eq(User::getPassword,"jerry");User user = userMapper.selectOne(lqw);System.out.println(user);}
eq(): 相當于 =,對應的sql語句為:SELECT id,name,password,age,tel FROM user WHERE (name = ? AND password = ?)
selectList:查詢結果為多個或者單個
selectOne:查詢結果為單個
2.范圍查詢
需求:對年齡進行范圍查詢,使用lt()、le()、gt()、ge()、between()進行范圍查詢
//范圍查詢@Testvoid testGetAll12(){LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<User>();lqw.between(User::getAge,10,30);List<User> users = userMapper.selectList(lqw);System.out.println(users);}
gt():大于(>)
ge():大于等于(>=)
lt():小于(<)
lte():小于等于(<=)
between():between ? and ?
3.查詢表中name屬性的值以J開頭的用戶信息,使用like進行模糊查詢
//模糊查詢@Testvoid testGetAll14(){LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<User>();lqw.like(User::getName,"J");List<User> users = userMapper.selectList(lqw);System.out.println(users);}
like():前后加百分號,如 %J%
likeLeft():前面加百分號,如 %J
likeRight():后面加百分號,如 J%
4.排序查詢::查詢所有數據,然后按照id降序
//排序查詢
// 需求:查詢所有數據,然后按照id降序@Testvoid testGetAll15(){LambdaQueryWrapper<User> lwq=new LambdaQueryWrapper<>();lwq.orderBy(true,false,User::getId);userMapper.selectList(lwq);}
?映射匹配兼容性
前面我們已經能從表中查詢出數據,并將數據封裝到模型類中,這整個過程涉及到一張表和一個模型類:
那么問題就來了:?
問題1:表字段與編碼屬性設計不同步
當表的列名和模型類的屬性名發生不一致,就會導致數據封裝不到模型對象,這個時候就需要其中一方做出修改,那如果前提是兩邊都不能改又該如何解決?
MP給我們提供了一個注解@TableField,使用該注解可以實現模型類屬性名和表的列名之間的映射關系
問題2:編碼中添加了數據庫中未定義的屬性?
當模型類中多了一個數據庫表不存在的字段,就會導致生成的sql語句中在select的時候查詢了數據庫不
存在的字段,程序運行就會報錯,錯誤信息為:
Unknown column '多出來的字段名稱' in 'field list'
具體的解決方案用到的還是@TableField注解,它有一個屬性叫exist,設置該字段是否在數據庫表
中存在,如果設置為false則不存在,生成sql語句查詢的時候,就不會再查詢該字段了。
?采用默認查詢開放了更多的字段查看權限

表名與編碼開發設計不同步?


DML編程控制

2.ID生成策略對比?
?簡化配置
只需要在配置文件中添加如下內容:?
mybatis-plus:global-config:db-config:id-type: assign_id
配置起來還是比較繁瑣,簡化方式為在配置文件中配置如下內容:?
mybatis-plus:global-config:db-config:table-prefix: tbl_
多記錄操作?
@Testvoid testDelete(){//刪除多條指定數據List<Long> list=new ArrayList<>();list.add(1402551342481838081L);list.add(1402551344241838054L);list.add(1402851342487778081L);userMapper.deleteBatchIds(list);}
//根據傳入的ID集合查詢用戶信息@Testvoid testGetByIds(){//查詢指定多條數據List<Long> list=new ArrayList<>();list.add(1L);list.add(2L);list.add(3L);userMapper.selectBatchIds(list);}

?實體類添加屬性
(1)添加與數據庫表的列對應的一個屬性名,名稱可以任意,如果和數據表列名對不上,可以使用 @TableField進行關系映射,如果一致,則會自動對應。
(2)標識新增的字段為邏輯刪除字段,使用 @TableLogic
?運行刪除方法
@Testvoid testDelete2(){userMapper.deleteById(1L);}

思考:邏輯刪除,對查詢有沒有影響呢?
執行查詢操作
@Testvoid testFind(){System.out.println(userMapper.selectList(null));}

?

樂觀鎖?
咱們可以把樂觀鎖的這個過程想象成兩個人借同一本書的場景,這樣就好理解了:
你可以把數據庫里的那條數據當成一本暢銷書,而version
列就像是這本書的 “借閱次數標簽”,一開始這標簽上寫著 “1”(默認值 1)。
現在有甲和乙兩個人都想借這本書,并且借完后要在標簽上把次數加 1。
- 甲先來借書,他看到標簽上是 “1”,心里記下了這個數字,打算借完后改成 “2”。
- 乙緊接著也來了,他看到的標簽也是 “1”,同樣打算借完后改成 “2”。
這時候就有兩種情況:
甲先借到了書,他按照自己的想法,把標簽從 “1” 改成了 “2”,然后把書還回去了。
等乙再來借書時,他拿出自己記下的 “1” 去核對標簽,發現標簽已經是 “2” 了,跟自己記的不一樣,就知道這本書被別人動過了,自己借不了了,只能放棄。要是乙先借到了書,他把標簽從 “1” 改成 “2” 還回去。
甲再來時,同樣發現標簽變成了 “2”,和自己記的 “1” 對不上,也借不了,只能放棄。所以不管是甲先還是乙先,最終只有一個人能成功借書并改標簽,另一個人會因為標簽對不上而失敗。這就是樂觀鎖的意思:它樂觀地認為大家不會搶著修改數據,但會通過 “版本號(version)” 來核對,一旦發現版本對不上,就說明數據被別人改過了,自己的修改就失敗,避免了沖突。


步驟3:添加樂觀鎖的攔截器
package com.apesource.spring_mybatis_plus_01.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MpConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){//1.定義Mp攔截器MybatisPlusInterceptor mybatisPlusInterceptor=new MybatisPlusInterceptor();//2.添加樂觀鎖攔截器mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return mybatisPlusInterceptor;}
}
?步驟4:執行更新操作
/*** 測試樂觀鎖*/@Testvoid testUpdate(){User user=new User();user.setId(4L);user.setName("王升1");userMapper.updateById(user);}
@Testvoid testUpdate2(){User user=new User();user.setId(4L);user.setName("王升2");user.setVersion(1);userMapper.updateById(user);}
@Testvoid testUpdate3(){//1.先通過要修改的數據id將當前數據查詢出來User user=userMapper.selectById(4L);//2.將要修改的屬性逐一設置進去user.setName("王升3");userMapper.updateById(user);}
@Testvoid testUpdate4(){User user=userMapper.selectById(3L);User user2=userMapper.selectById(3L);user2.setName("Jock aaa");userMapper.updateById(user2);user.setName("Jock bbb");userMapper.updateById(user);}