一、條件查詢的類
這個我們在前面都有見過,比如查詢所有和分頁查詢的時候,都有看到過一個Wrapper
類,這個類就是用來構建查詢條件的,如下圖所示:
那麼條件查詢如何使用Wrapper來構建呢?
二、環境構建
在構建條件查詢之前,我們先來準備下環境
-
創建一個SpringBoot項目
參考Java開發學習(三十五)----SpringBoot快速入門及起步依賴解析
-
pom.xml中添加對應的依賴
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.0</version> </parent> <groupId>com.itheima</groupId> <artifactId>mybatisplus_02_dql</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
編寫UserDao接口
@Mapper public interface UserDao extends BaseMapper<User> { }
-
編寫模型類
@Data public class User { private Long id; private String name; private String password; private Integer age; private String tel; }
-
編寫引導類
@SpringBootApplication public class Mybatisplus02DqlApplication { public static void main(String[] args) { SpringApplication.run(Mybatisplus02DqlApplication.class, args); } }
-
編寫配置文件
# dataSource spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC username: root password: root # MybatisPlus日誌 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
-
編寫測試類
@SpringBootTest class Mybatisplus02DqlApplicationTests { @Autowired private UserDao userDao; @Test void testGetAll(){ List<User> userList = userDao.selectList(null); System.out.println(userList); } }
最終創建的項目結構爲:
-
測試的時候,控制檯打印的日誌比較多,速度有點慢而且不利於查看運行結果,所以接下來我們把這個日誌處理下:
-
取消初始化spring日誌打印,resources目錄下添加logback.xml,名稱固定,內容如下:
<?xml version="1.0" encoding="UTF-8"?> <configuration> </configuration>
-
取消MybatisPlus啓動banner圖標
application.yml添加如下內容:
# mybatis-plus日誌控制檯輸出 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: banner: off # 關閉mybatisplus啓動圖標
-
取消SpringBoot的log打印
application.yml添加如下內容:
spring: main: banner-mode: off # 關閉SpringBoot啓動圖標(banner)
-
解決控制檯打印日誌過多的相關操作可以不用去做,一般會被用來方便我們查看程序運行的結果。
三、構建條件查詢
在進行查詢的時候,我們的入口是在Wrapper這個類上,因爲它是一個接口,所以我們需要去找它對應的實現類,關於實現類也有很多,說明我們有多種構建查詢條件對象的方式,
-
先來看第一種:QueryWrapper
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll(){
QueryWrapper qw = new QueryWrapper();
qw.lt("age",18);
List<User> userList = userDao.selectList(qw);
System.out.println(userList);
}
}
-
lt: 小於(<) ,最終的sql語句爲
SELECT id,name,password,age,tel FROM user WHERE (age < ?)
第一種方式介紹完後,有個小問題就是在寫條件的時候,容易出錯,比如age寫錯,就會導致查詢不成功
-
接着來看第二種:QueryWrapper的基礎上使用lambda
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll(){
QueryWrapper<User> qw = new QueryWrapper<User>();
qw.lambda().lt(User::getAge, 10);//添加條件
List<User> userList = userDao.selectList(qw);
System.out.println(userList);
}
}
-
User::getAge,爲lambda表達式中的,類名::方法名,最終的sql語句爲:
SELECT id,name,password,age,tel FROM user WHERE (age < ?)
注意:構建LambdaQueryWrapper的時候泛型不能省。
此時我們再次編寫條件的時候,就不會存在寫錯名稱的情況,但是qw後面多了一層lambda()調用
-
接着來看第三種:LambdaQueryWrapper
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
這種方式就解決了上一種方式所存在的問題。
四、多條件構建
三種構建查詢對象的方式,每一種都有自己的特點,所以用哪一種都行,剛纔都是一個條件,那如果有多個條件該如何構建呢?
需求:查詢數據庫表中,年齡在10歲到30歲之間的用戶信息
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, 30);
lqw.gt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
-
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的數據
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
-
or()就相當於我們sql語句中的
or
關鍵字,不加默認是and
,最終的sql語句爲:SELECT id,name,password,age,tel FROM user WHERE (age < ? OR age > ?)
五、null判定
先來看一張圖,
-
我們在做條件查詢的時候,一般會有很多條件可以供用戶進行選擇查詢。
-
這些條件用戶可以選擇使用也可以選擇不使用,比如我要查詢價格在8000以上的手機
-
在輸入條件的時候,價格有一個區間範圍,按照需求只需要在第一個價格輸入框中輸入8000
-
後臺在做價格查詢的時候,一般會讓 price>值1 and price <值2
-
因爲前端沒有輸入值2,所以如果不處理的話,就會出現 price>8000 and price < null問題
-
這個時候查詢的結果就會出問題,具體該如何解決?
需求:查詢數據庫表中,根據輸入年齡範圍來查詢符合條件的記錄
用戶在輸入值的時候,
如果只輸入第一個框,說明要查詢大於該年齡的用戶
如果只輸入第二個框,說明要查詢小於該年齡的用戶
如果兩個框都輸入了,說明要查詢年齡在兩個範圍之間的用戶
思考第一個問題:後臺如果想接收前端的兩個數據,該如何接收?
我們可以使用兩個簡單數據類型,也可以使用一個模型類,但是User類中目前只有一個age屬性,如:
@Data
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
}
使用一個age屬性,如何去接收頁面上的兩個值呢?這個時候我們有兩個解決方案
方案一:添加屬性age2,這種做法可以但是會影響到原模型類的屬性內容
@Data
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
private Integer age2;
}
方案二:新建一個模型類,讓其繼承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;
}
環境準備好後,我們來實現下剛纔的需求:
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void 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);
}
}
上面的寫法可以完成條件爲非空的判斷,但是問題很明顯,如果條件多的話,每個條件都需要判斷,代碼量就比較大,來看MybatisPlus給我們提供的簡化方式:
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void 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);
}
}
-
lt()方法
condition爲boolean類型,返回true,則添加條件,返回false則不添加條件