一篇文章帶你掌握MyBatis簡化框架——MyBatisPlus
我們在前面的文章中已經學習了目前開發所需的主流框架
類似于我們所學習的SpringBoot框架用于簡化Spring開發,我們的國人大大也開發了一款MyBatisPlus框架用來簡化MyBatis開發
下面讓我們來逐步掌握MyBatisPlus的內容吧~
MyBatisPlus簡介
首先我們來簡單介紹一下MyBatisPlus:
- MyBatisPlus(MP)是基于MyBatis框架基礎上開發的增強型工具,旨在簡化開發,提高效率
MyBatisPlus開發具有三種開發方式:
- 基于MyBatis使用MyBatisPlus
- 基于Spring使用MyBatisPlus
- 基于SpringBoot使用MyBatisPlus
MyBatisPlus入門案例
我們以基于SpringBoot使用MyBatisPlus為案例來展示MyBatisPlus開發的便捷性
SpringBoot使用MyBatis
首先我們回憶一下SpringBoot使用MyBatis開發的相關步驟:
- 創建SpringBoot工程
- 勾選配置使用技術
- 設定DataSource相關屬性(JDBC引數)
- 定義資料層介面映射配置
其中最為繁瑣的就是資料層介面的配置,需要書寫大量的@注解來進行資料庫的查詢
package com.itheima.dao;
import com.itheima.domain.Book;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface BookDao {
@Insert("insert into tbl_book (type,name,description) values(#{type},#{name},#{description})")
public int save(Book book);
@Update("update tbl_book set type = #{type}, name = #{name}, description = #{description} where id = #{id}")
public int update(Book book);
@Delete("delete from tbl_book where id = #{id}")
public int delete(Integer id);
@Select("select * from tbl_book where id = #{id}")
public Book getById(Integer id);
@Select("select * from tbl_book")
public List<Book> getAll();
}
SpringBoot使用MyBatisPlus
我們的SpringBoot使用MyBatisPlus大量簡化了資料層代碼書寫
我們下面依次介紹整體步驟:
- 創建專案(SpringBoot專案,勾選相應技術堆疊)

- 匯入相關依賴坐標
<?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>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itheima</groupId>
<artifactId>mybatisplus_01_quickstart</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--由于SpringBoot中未整合MyBatisPlus,所以我們需要手動添加MyBatisPlus依賴坐標-->
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 配置環境yaml
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
- 書寫資料庫物體類
package com.itheima.domain;
import lombok.*;
@Data
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
@java.lang.Override
public java.lang.String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
", age=" + age +
", tel='" + tel + '\'' +
'}';
}
}
- 資料層書寫
package com.itheima.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.Mapper;
// @Mapper為了使掃描到該資料層包(SpringBoot中提及)
@Mapper
// 注意:MyBatisPlus不需要書寫方法,我們直接繼承BaseMapper類,并表明我們所使用的物體類即可
public interface UserDao extends BaseMapper<User> {
// 不需要書寫方法,在BaseMapper類中為我們配置了大量的資料庫方法來查詢,新增,修改,洗掉
}
- 測驗
package com.itheima;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
// 我們只需要得到UserDao類,并呼叫其方法即可(MyBatisPlus提供方法)
// 在這里我們僅呼叫selectById方法,當作測驗
@Test
void testGetById(){
User user = userDao.selectById(2L);
System.out.println(user);
}
}
至此,我們的第一個MyBatisPlus案例就結束了
MyBatisPlus概述
在使用過MyBatisPlus后,我們就可以重新介紹一下MyBatisPlus了:
- MyBatisPlus(MP)是基于MyBatis框架基礎上開發的增強型工具,旨在簡化開發,提高效率
- 官網:MyBatis-Plus (baomidou.com)
MyBatisPlus特征:
- 無侵入:制作增強,不做改變,不會對現有工程產生影響
- 強大的CRUD操作:內置通用的Mapper,少量配置即可實作單表CRUD操作
- 支持Lambda:撰寫查詢條件無需擔心欄位錯誤
- 支持逐漸自動生成
- 內置分頁插件
最后提及一句:MyBatisPlus是由國人開發,官網也是以中文書寫,具有中國風范~
標準資料層開發
我們在前面已經大致掌握了MyBatisPlus的具體操作流程,下面讓我們更加細膩的分析資料層開發
Lombok依賴坐標
在正式開始講解資料層開發前,為大家提供一個簡單可靠的依賴:
- Lombok依賴
那么這個坐標具有什么作用呢
- Lombok依賴可以用來簡化物體類的開發
- Lombok,屬于Java類別庫,提供了一組注解,簡化POJO物體類開發
我們采用一個簡單的案例來展示:
- 首先我們需要匯入該坐標
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
- 我們的物體類中產生多個新注解
package com.itheima.domain;
import lombok.*;
//lombok
@Data
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
}
/*
lombok為我們提供了多個注解:
@Setter:提供所有set方法
@Getter:提供所有Get方法
@ToString:提供ToString重構方法
@NoArgsConstructor:無參構造
@AllArgsConstructor:有參構造
其中我們最常用的注解是:
@Data:包括了除建構式外的所有方法(Set,Get,ToString,hashCode,equals)
*/
標準資料層開發(簡單版)
首先我們來列出一些我們通常開發中會使用的資料層陳述句:
| 功能 | MP介面 |
|---|---|
| 新增 | int insert(T t) |
| 洗掉 | int deleteById(Serializable id) |
| 修改 | int updateById(T t) |
| 根據id查詢 | T selectById(Serializable id) |
| 查詢全部 | List |
上述方法我們無需在資料層定義,直接測驗即可:
package com.itheima;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
// 自動裝配資料層
@Autowired
private UserDao userDao;
// 注意:id的資料型別為LONG,數值后需要加L
// 注意:下述部分方法需要回傳id,物體類,null
// 新增
@Test
void testSave(){
User user = new User();
user.setName("黑馬程式員");
user.setPassword("itheima");
user.setAge(12);
user.setTel("4006184000");
userDao.insert(user);
}
// 洗掉
@Test
void testDelete(){
userDao.deleteById(1L);
}
// 更新(注意:根據id進行更新,更新與原資料不同的數值,null值不進行更新)
@Test
void testUpdate(){
User user = new User();
user.setId(1L);
user.setName("Tom888");
user.setPassword("tom888");
userDao.updateById(user);
}
// 根據id查詢
@Test
void testGetById(){
User user = userDao.selectById(2L);
System.out.println(user);
}
// 查詢全部
@Test
void testGetAll() {
List<User> userList = userDao.selectList(null);
System.out.println(userList);
}
}
標準資料層開發(分頁查詢)
我們將分頁查詢單獨列為一個小節進行講解:
| 功能 | MP介面 |
|---|---|
| 分頁查詢 | IPage<T> selectPage(IPage<T> page) |
MyBatisPlus的分頁查詢需要一些前置條件,我們下面一一講述:
- 添加攔截器,進行分頁操作:
// MyBatisPlus的分頁操作需要添加攔截器
// 我們在Java檔案夾下創建Config檔案夾,創建MPConfig的Java類作為配置類
package com.itheima.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 作為配置類,讓spring可以直接掃描
@Configuration
public class MpConfig {
// 需要設定為Bean
@Bean
public MybatisPlusInterceptor mpInterceptor(){
//1.定義Mp攔截器MybatisPlusInterceptor(相當于外層攔截器)
MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
//2.添加具體的攔截器PaginationInnerInterceptor(相當于在大攔截器中添加小攔截器)
mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mpInterceptor;
}
}
- 直接測驗即可
package com.itheima;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class Mybatisplus01QuickstartApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetByPage(){
// selectPage需要兩個引數IPage和Wrapper,IPage具有Page的實作類,Wrapper我們會在后續講到,這里暫設為null
//IPage物件封裝了分頁操作相關的資料,第一個引數為開始數,第二個數為本頁可展示資料數
IPage page = new Page(2,3);
userDao.selectPage(page,null);
// 下述為page本身攜帶的一些方法,用于查看相關資料
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());
}
}
- 查看日志
# 如果我們想要查看實際開發的資料庫陳述句,我們可以選擇開啟日志進行查看
# 查看日志方法設定在yaml組態檔中
# 開啟mp的日志(輸出到控制臺)
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
DQL編程控制
我們在前面已經講解了簡單的資料層開發,下面我們將會進一步講解DQL的編程內容
清除版本圖
在正式開始前,我們講一些簡單輕松的知識點:
- 我們在每次開啟服務器后都會出現SpringBoot和MyBatisPlus的版本圖,有時會影響我們代碼的閱讀

那么我們該如何清除呢
- 設定logback.xml檔案
<!--我們在sources中新創一個spring config 檔案-->
<!--設定一個configuration雙標簽,不用填寫內容即可-->
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
</configuration>
- 在yaml組態檔中做清除作業
# 我們只需要將spring和MyBatisPlus的banner設定為false即可關閉版本圖
# 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
main:
banner-mode: off
# mp日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: false
基本條件查詢
在介紹條件查詢前,我們需要先來介紹Wrapper:
- Wrapper屬于一種介面引數
- Wrapper是我們的條件查詢中所攜帶的進行條件判斷的引數
- 介面方法的引數中,會出現各種 Wrapper,比如 queryWrapper、updateWrapper 等
接下來我們就來介紹三種基本條件查詢:
- 按條件查詢
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//方式一:按條件查詢
// 我們的條件查詢一般采用QueryWrapper型別的類來創造Wrapper條件判斷引數
QueryWrapper qw = new QueryWrapper();
// 我們采用QueryWrapper的一些方法來進行給予判斷條件,后續我們會進行介紹
// 這里采用lt小于方法,后面跟String型別字串代表資料庫列名,在跟數值表示值
qw.lt("age",18);
// 我們采用userDao的selectList方法根據qw條件判斷機制來進行獲取資料
// 獲取了User數值的List,并列印即可
List<User> userList = userDao.selectList(qw);
System.out.println(userList);
}
}
- lambda格式按條件查詢(方法版)
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//方式二:lambda格式按條件查詢
QueryWrapper<User> qw = new QueryWrapper<User>();
// MyBatisPlus可支持Lambda運算式,我們使用lambda方法使后續操作均變為Lambda運算式形式
// 我們的String資料庫列名可以采用Lambda運算式形式書寫
qw.lambda().lt(User::getAge, 10);
List<User> userList = userDao.selectList(qw);
System.out.println(userList);
}
}
- lambda格式按條件查詢(繼承類版)
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//方式三:lambda格式按條件查詢
// 這里直接繼承LambdaQueryWrapper,后續操作可以直接采用Lambda運算式,不用攜帶方法lambda
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
除了上面三種基本條件查詢外,我們可以發現條件查詢是可以疊加使用的,主要分為兩種疊加方式:
- 正常疊加
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 10到30歲之間
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);
}
}
- 鏈式疊加
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 10到30歲之間
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);
}
}
最后我們還要介紹兩種組合查詢條件形式:
- 并且(and)
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//并且關系
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//并且關系:10到30歲之間(直接鏈式書寫即可)
lqw.lt(User::getAge, 30).gt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
- 或者(or)
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//或者關系
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//或者關系:小于10歲或者大于30歲(在條件之間采用or方法來隔離)
lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
空值處理
我們在做實際專案處理時,會出現各種查詢框架
例如價格查詢搜索產品,但我們可能不會同時給出最低價限制和最高價限制
我們以代碼來做一個簡單示例:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 模擬頁面傳遞過來的查詢資料
UserQuery uq = new UserQuery();
// 如果我們下面的資料有一個沒有設定,就會導致查詢陳述句中的?沒有填充,導致搜索失敗
uq.setAge(10);
uq.setAge2(null);
// null判定
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, uq.getAge2());
lqw.gt(User::getAge, uq.getAge());
List<User> userList = userDao.selectList(lqw);
System.out.println(userList)
}
}
在之前我們的null值處理大部分都是采用if陳述句來進行判斷:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 模擬頁面傳遞過來的查詢資料
UserQuery uq = new UserQuery();
// 可能出現有任意一個數沒有賦值
uq.setAge(10);
uq.setAge2(null);
// null判定
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, uq.getAge2());
// 正常我們采用if來進行判斷是否有值,若有值則加入操作
// 但當if陳述句過多,導致代碼冗雜
if( null != uq.getAge()) {
lqw.gt(User::getAge, uq.getAge());
}
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
MyBatisPlus給出了一種新的判定方法來決定是否加載該陳述句:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 模擬頁面傳遞過來的查詢資料
UserQuery uq = new UserQuery();
uq.setAge(10);
uq.setAge2(30);
// LambdaQueryWrapper的各種方法中均攜帶了一個判定條件在最前面的引數中,當成立執行后續操作,不成立直接跳過
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
// 先判定第一個引數是否為true,如果為true連接當前條件
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);
}
}
查詢投影
我們選擇性的查詢資料庫列稱為查詢投影,接下來讓我們來介紹查詢投影的實作方法
查詢投影的實作我們大致分為兩種型別:
- 查詢結果包含模型類中部分屬性
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 查詢投影
// 當我們所查詢的內容屬于物體類中包含的屬性,我們可以采用QW或LambdaQW來實作
// 我們大部分采用LambdaQW來實作,因為帶有自動識別,不易出錯
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
// 我們采用select方法來添加查詢種類,LambdaQueryWrapper采用Lambda運算式添加
lqw.select(User::getId,User::getName,User::getAge);
QueryWrapper<User> lqw = new QueryWrapper<User>();
// 我們采用select方法來添加查詢種類,QueryWrapper采用String添加
lqw.select("id","name","age","tel");
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
- 查詢結果包含模型類中未定義屬性
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
// 查詢投影
// 未定義的屬性我們只能采用QueryWrapper的String字串來書寫,例如count(*)和分組條件
QueryWrapper<User> lqw = new QueryWrapper<User>();
lqw.select("count(*) as count, tel");
// QueryWrapper提供了分組方法groupBy,引數為String型別的資料庫列名
lqw.groupBy("tel");
List<Map<String, Object>> userList = userDao.selectMaps(lqw);
System.out.println(userList);
}
}
查詢條件展示
首先我們給出所有查詢條件官網鏈接:條件構造器 | MyBatis-Plus (baomidou.com)

如果有需要可以上網查詢相關構造方法
下面我們僅對一些常用查詢條件進行展示:
package com.itheima;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import com.itheima.domain.query.UserQuery;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Map;
@SpringBootTest
class Mybatisplus02DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testGetAll() {
//條件查詢
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
// eq等同于=
lqw.eq(User::getName,"Jerry").eq(User::getPassword,"jerry");
User loginUser = userDao.selectOne(lqw);
System.out.println(loginUser);
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//范圍查詢 lt le gt ge eq between
lqw.between(User::getAge,10,30);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//模糊匹配 like
lqw.likeLeft(User::getName,"J");
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
// 查詢全部
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
}
}
映射處理
最后介紹的依舊是我們在MyBatis中也出現的老問題:
- 當我們的實作類和資料庫表出現不同點時我們該如何處理
我們在下面分為幾種情況來講解:
- 表名與編碼開發設計不同步
// 假設我們的資料庫表名為tbl_user,但我們的物體類設計為User
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
// 采用注解@TableName,后面跟對應的資料庫表名
@TableName("tbl_user")
public class User {
private Long id;
private String name;
private String password;
private Integer age;
private String tel;
}
- 列名與編碼開發設計不同步
// 假設我們的資料庫密碼設計為pwd,但是我們的物體類密碼屬性設計為password
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
//lombok
@Data
@TableName("tbl_user")
public class User {
private Long id;
private String name;
// 采用@TableField注解,后面采用屬性value=https://www.cnblogs.com/qiuluoyuweiliang/p/資料庫列名
@TableField(value ="pwd")
private String password;
private Integer age;
private String tel;
}
- 該列不應當被列印時
// 例如我們的pwd密碼,在查詢時不應當被查詢,但是我們采用select * from tbl_user來查詢,如何屏蔽
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
//lombok
@Data
@TableName("tbl_user")
public class User {
private Long id;
private String name;
// 采用@TableField注解,后面采用屬性select設定為false,即為不可查詢
@TableField(value = "https://www.cnblogs.com/qiuluoyuweiliang/p/pwd",select = false)
private String password;
private Integer age;
private String tel;
}
- 當物體類中出現資料庫中不存在的列時
// 例如我們設計了一個屬性online判斷是否在線,不用放于資料庫中,我們該如何在select * 中去除該屬性
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
//lombok
@Data
@TableName("tbl_user")
public class User {
private Long id;
private String name;
@TableField(value = "https://www.cnblogs.com/qiuluoyuweiliang/p/pwd",select = false)
private String password;
private Integer age;
private String tel;
// 采用@TableField注解,后面跟屬性exist設定為false,則判斷該屬性不存在于資料庫中
@TableField(exist = false)
private Integer online;
}
我們將上述內容分離出來主要解釋兩個注解:
- @TableName
- 名稱:@TableName
- 型別:類注解
- 位置:模型類定義上方
- 作用:設定當前類對應的資料庫表關系
- 相關屬性:value設定資料庫表名稱
- @TableField
- 名稱:@TableField
- 型別:屬性注解
- 位置:模型類屬性定義上方
- 作用:設定當前屬性眾多關系
- 相關屬性:value設定資料庫欄位名稱,exist設定屬性在資料庫欄位中是否存在,select設定屬性是否參與查詢
DML編程控制
這一章節我們來講一些MyBatisPlus中經常用到的操作,下面我們一一介紹
ID生成策略控制
我們在實際開發中會有需要ID生成需求,對于不同的情況需要采取不同的ID生成方法:
- 員工編號:遞增ID生成
- 快遞單號:地區ID生成
- 網路編號:隨機ID生成
因此MyBatisPlus提供了一種新的注解來實作這類需求:
- 名稱:@TableId
- 型別:屬性注解
- 位置:模型類中用于表示主鍵的屬性定義上方
- 作用:設定當前類中主鍵屬性的生成策略
- 相關屬性:value設定資料庫主鍵名稱,type設定主鍵生成策略具體參考IdType列舉值
ID生成策略列舉值:
- AUTO(0):使用資料庫id自增策略控制id生成
- NONE(1):不設定ID生成策略
- INPUT(2):用戶手工輸入ID
- ASSIGN_ID(3):雪花演算法生成ID(可兼容數值型與字串型)
- ASSIGN_UUID(4):以UUID生成演算法作為ID生成策略
我們給出示例演示:
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
@Data
//設定表名映射關系
@TableName("tbl_user")
public class User {
//設定主鍵生成策略(這里設定為自增)
@TableId(type = IdType.AUTO)
private Long id;
private String name;
@TableField(value = "https://www.cnblogs.com/qiuluoyuweiliang/p/pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer online;
private Integer deleted;
private Integer version;
}
我們也可以同一設定@TableId的type屬性,使整個專案的@TableId都以一種形態執行:
# 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
main:
banner-mode: off
# mp日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: false
db-config:
id-type: assign_id # 設定為雪花演算法設定ID
多記錄操作
我們在實際開發中常常會進行多條記錄操作:
- 根據主鍵洗掉多條操作
- 根據主鍵查詢多條操作
MyBatisPlus也為我們提供了相對應的方法:
package com.itheima;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
class Mybatisplus03DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testDelete(){
//洗掉指定多條資料
//deleteBatchIds引數為陣列形式,我們提供id的陣列即可
List<Long> list = new ArrayList<>();
list.add(1402551342481838081L);
list.add(1402553134049501186L);
list.add(1402553619611430913L);
userDao.deleteBatchIds(list);
}
@Test
void testSelect()}{
//查詢指定多條資料
//selectBatchIds引數為陣列形式,我們提供id的陣列即可
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(3L);
list.add(4L);
userDao.selectBatchIds(list);
}
}
邏輯洗掉
我們在實際開發中面對專案的洗掉操作有時并非是真正的洗掉操作:
- 例如對于一些資料的存盤,我們需要在年終總結中計算總產量,所以所有利益收入不能洗掉
- 但對于一些離職的員工,關于他們的資料需要暫時性洗掉,因而產生矛盾
因而我們提出了邏輯洗掉的概念:
- 我們在總串列中添加一個屬性deleted來設定是否被洗掉
- 當deleted為1時,當作資料洗掉;當deleted為1時,當作資料存在
- 我們在實際開發中以一種虛擬的洗掉思想(邏輯洗掉)來代替真正的資料洗掉
下面我們來講解如何在MyBatisPlus中實作這種思想:
- 資料庫中添加deleted列
ALTER TABLE tb_user ADD deleted int(1) DEFAULT 0;
- 物體庫中添加deleted屬性,并用注解注明為邏輯洗掉屬性
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
@Data
//設定表名映射關系
@TableName("tbl_user")
public class User {
//設定主鍵生成策略
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
@TableField(value = "https://www.cnblogs.com/qiuluoyuweiliang/p/pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer online;
//邏輯洗掉欄位,標記當前記錄是否被洗掉(value原值,delval修改值)
@TableLogic(value = "https://www.cnblogs.com/qiuluoyuweiliang/p/0" ,delval = "1")
private Integer deleted;
}
/*
@TableLogic
在設定之后,我們采用delete方法時,不會直接洗掉資料,而是將該資料值從value變為delval
類似于:UPDATE tbl_user SET deleted = 1 WHERE id = ? AND deleted = 0;
*/
同樣,我們的邏輯洗掉值也可以進行統一設定:
# 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
main:
banner-mode: off
# mp日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
banner: false
db-config:
id-type: assign_id
table-prefix: tbl_
# 邏輯洗掉欄位名
logic-delete-field: deleted
# 邏輯洗掉字面值:未洗掉為0
logic-not-delete-value: 0
# 邏輯洗掉字面值:洗掉為1
logic-delete-value: 1
樂觀鎖
我們在業務開發中也會遇到多執行緒的問題:
- 例如我們的秒殺活動,在之前多執行緒中也有提及過的問題
- 如果我們不希望我們的剩余商品數變為負數,那么就需要設定Lock來解決這個問題
首先我們來講解一下樂觀鎖的基本概念:
- 樂觀鎖首先讀取當前該商品的狀態
- 然后利用當前商品的狀態為條件來修改商品狀態,并且將該商品狀態進行修改
- 如果用戶A和用戶B同時讀取商品狀態,當用戶A的WHERE條件成立后修改商品,則用戶B的WHERE條件就不再成立無法修改
在MyBatisPlus中我們采用樂觀鎖的概念來解決:
- 在資料庫中新添version屬性
ALTER TABLE tb_user ADD version int(11) DEFAULT 1;
- 物體類中新添version屬性并加上注解
package com.itheima.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
@Data
//設定表名映射關系
@TableName("tbl_user")
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
@TableField(value = "https://www.cnblogs.com/qiuluoyuweiliang/p/pwd",select = false)
private String password;
private Integer age;
private String tel;
@TableField(exist = false)
private Integer online;
@TableLogic(value = "https://www.cnblogs.com/qiuluoyuweiliang/p/0" ,delval = "1")
private Integer deleted;
// version版本注解(樂觀鎖)
@Version
private Integer version;
}
- 使用攔截器
/*
我們來講解一下為什么需要使用攔截器
我們將前面我們介紹的樂觀鎖概念轉化為陳述句:
SELETE version FROM tbl_user
UPDATE tbl_user SET ...(用戶修改) version=version+1 WHERE id = ? AND version = version(我們之前讀取的version)
倘若用戶操作前有其他用戶操作,那么version就會發生變化,導致用戶無法找到對應的資料,無法操作
因為我們需要對前面的version進行修改,我們需要將陳述句攔截下來進行一定修改,所以這里采用攔截器
*/
package com.itheima.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor mpInterceptor() {
//1.定義Mp攔截器
MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
//2.添加具體的攔截器
mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
//3.添加樂觀鎖攔截器
mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mpInterceptor;
}
}
- 測驗
package com.itheima;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest
class Mybatisplus03DqlApplicationTests {
@Autowired
private UserDao userDao;
@Test
void testUpdate(){
// 我們設定一個實體User,id為1,version為1
User user = new User();
user.setId(1L);
user.setName("Jock666");
user.setVersion(1);
userDao.updateById(user);
// 我們用user,user2來當作兩個用戶
// 假設兩個用戶同時讀取資料
User user = userDao.selectById(3L); //version=1
User user2 = userDao.selectById(3L); //version=1
// user用戶首先進行操作(這時 實體version為1 操作成立 ,操作結束后version變為2)
// UPDATE tbl_user SET ...(用戶修改) version=2 WHERE id = 1 AND version = 1
user.setName("Jock aaa");
userDao.updateById(user2);
// user2用戶開始操作(這時 實體version為2 但前面讀取的version為1,讀取不到資料,無法操作)
// UPDATE tbl_user SET ...(用戶修改) version=2 WHERE id = 1 AND version = 1(已讀取不到資料)
user2.setName("Jock bbb");
userDao.updateById(user);
}
}
結束語
好的,關于MyBatisPlus的內容就介紹到這里,希望能為你帶來幫助!
附錄
該文章屬于學習內容,具體參考B站黑馬程式員李老師的SSM框架課程
這里附上鏈接:MyBatisPlus-01-MybatisPlus入門案例_嗶哩嗶哩_bilibili
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/516446.html
標籤:架構設計
上一篇:現在能夠以角度從物件讀取資料
下一篇:初識設計模式 - 觀察者模式
