MyBatis-Plus(簡(jiǎn)稱 MP)是一個(gè) MyBatis 的增強(qiáng)工具捉撮,在 MyBatis 的基礎(chǔ)上只做增強(qiáng)不做改變奋救,為簡(jiǎn)化開(kāi)發(fā)、提高效率而生。
特性
- 無(wú)侵入:只做增強(qiáng)不做改變授嘀,引入它不會(huì)對(duì)現(xiàn)有工程產(chǎn)生影響,如絲般順滑
- 損耗小:?jiǎn)?dòng)即會(huì)自動(dòng)注入基本 CURD锣险,性能基本無(wú)損耗蹄皱,直接面向?qū)ο蟛僮?/li>
- 強(qiáng)大的 CRUD 操作:內(nèi)置通用 Mapper、通用 Service芯肤,僅僅通過(guò)少量配置即可實(shí)現(xiàn)單表大部分 CRUD 操作巷折,更有強(qiáng)大的條件構(gòu)造器,滿足各類使用需求
- 支持 Lambda 形式調(diào)用:通過(guò) Lambda 表達(dá)式崖咨,方便的編寫各類查詢條件锻拘,無(wú)需再擔(dān)心字段寫錯(cuò)
- 支持主鍵自動(dòng)生成:支持多達(dá) 4 種主鍵策略(內(nèi)含分布式唯一 ID 生成器 - Sequence),可自由配置击蹲,完美解決主鍵問(wèn)題
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式調(diào)用署拟,實(shí)體類只需繼承 Model 類即可進(jìn)行強(qiáng)大的 CRUD 操作
- 支持自定義全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 內(nèi)置代碼生成器:采用代碼或者 Maven 插件可快速生成 Mapper 、 Model 歌豺、 Service 推穷、 Controller 層代碼,支持模板引擎类咧,更有超多自定義配置等您來(lái)使用
- 內(nèi)置分頁(yè)插件:基于 MyBatis 物理分頁(yè)馒铃,開(kāi)發(fā)者無(wú)需關(guān)心具體操作蟹腾,配置好插件之后,寫分頁(yè)等同于普通 List 查詢
- 分頁(yè)插件支持多種數(shù)據(jù)庫(kù):支持 MySQL区宇、MariaDB娃殖、Oracle、DB2议谷、H2珊随、HSQL、SQLite柿隙、Postgre叶洞、SQLServer 等多種數(shù)據(jù)庫(kù)
- 內(nèi)置性能分析插件:可輸出 Sql 語(yǔ)句以及其執(zhí)行時(shí)間,建議開(kāi)發(fā)測(cè)試時(shí)啟用該功能禀崖,能快速揪出慢查詢
- 內(nèi)置全局?jǐn)r截插件:提供全表 delete 衩辟、 update 操作智能分析阻斷,也可自定義攔截規(guī)則波附,預(yù)防誤操作
支持?jǐn)?shù)據(jù)庫(kù)
mysql 艺晴、mariadb 、oracle 掸屡、db2 封寞、h2 、hsql 仅财、sqlite 狈究、postgresql 、sqlserver 盏求、presto 抖锥、Gauss 、Firebird
Phoenix 碎罚、clickhouse 磅废、Sybase ASE 、 OceanBase 荆烈、達(dá)夢(mèng)數(shù)據(jù)庫(kù) 拯勉、虛谷數(shù)據(jù)庫(kù) 、人大金倉(cāng)數(shù)據(jù)庫(kù) 憔购、南大通用數(shù)據(jù)庫(kù) 宫峦、
框架結(jié)構(gòu)
快速開(kāi)始
以springboot項(xiàng)目為例
引入mybatisPlus的依賴:
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
完整依賴如下:
<?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.3.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tp</groupId>
<artifactId>demo-mp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-mp</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql驅(qū)動(dòng) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional> <!-- 標(biāo)識(shí)依賴不會(huì)傳遞 -->
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.1</version>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置數(shù)據(jù)庫(kù)連接信息
server:
port: 7269
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
url: jdbc:mysql://localhost:3306/mybatis_plus_demo?useSSL=true&serverTimezone=GMT%2B8
username: root
password: tp123456
logging:
level:
root: info
com.tp: debug
創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for USER
-- ----------------------------
DROP TABLE IF EXISTS `USER`;
CREATE TABLE `USER` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年齡',
`email` varchar(50) DEFAULT NULL COMMENT '郵箱',
`manager_id` bigint(20) DEFAULT NULL COMMENT '直屬上級(jí)ID',
`create_time` datetime DEFAULT NULL COMMENT '郵箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
SET FOREIGN_KEY_CHECKS = 1;
項(xiàng)目中創(chuàng)建實(shí)體User.java
@Data
@TableName("user")
public class User {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/** 姓名 */
private String name;
/** 年齡 */
private Integer age;
/** 郵箱 */
private String email;
/** 直屬上級(jí)ID */
private Integer managerId;
/** 創(chuàng)建時(shí)間 */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") //此注解用來(lái)接收字符串類型的參數(shù)封裝成LocalDateTime類型
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") //此注解將date類型數(shù)據(jù)轉(zhuǎn)成字符串響應(yīng)出去
private LocalDateTime createTime;
/** 對(duì)于數(shù)據(jù)庫(kù)中沒(méi)有的字段,如果我們不處理倦始,在新增或修改的時(shí)候會(huì)出現(xiàn)錯(cuò)誤斗遏,mp為我們提供了注解@TableField解決此類問(wèn)題 */
@TableField(exist = false) // exist = false標(biāo)識(shí)數(shù)據(jù)庫(kù)沒(méi)有此字段,告訴mp映射時(shí)忽略此字段鞋邑,防止出現(xiàn)錯(cuò)誤诵次,默認(rèn)為true
List<Integer> roleIds;
}
注意:對(duì)于數(shù)據(jù)庫(kù)中沒(méi)有的字段账蓉,如果我們不做特殊處理,我們?cè)诓僮鲾?shù)據(jù)庫(kù)時(shí)MP會(huì)給我們自動(dòng)進(jìn)行映射逾一,但是因?yàn)閿?shù)據(jù)庫(kù)中并沒(méi)有這個(gè)字段铸本,這樣就會(huì)報(bào)錯(cuò):
org.springframework.jdbc.BadSqlGrammarException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column 'role_ids' in 'field list'
針對(duì)這種情形,我們可以使用MP提供的注解@TableField(exist = false)
來(lái)表明某個(gè)字段不是數(shù)據(jù)庫(kù)的字段遵堵,其中exist表示是否存在箱玷,默認(rèn)為true
創(chuàng)建Mapper,繼承自MP給我提供的BaseMapper
package com.tp.demo.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tp.demo.mp.entity.User;
/**
* FileName: UserMapper
* Author: TP
* Description: 用戶服務(wù)Mapper
*/
public interface UserMapper extends BaseMapper<User> {
}
接下來(lái)就可以測(cè)試?yán)材八蓿瑢?shí)際開(kāi)發(fā)中我們應(yīng)該寫Service锡足,但是這里為了方便,就不寫了
常用增刪改查
新增:
package com.tp.demo.mp;
import com.tp.demo.mp.entity.User;
import com.tp.demo.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.time.LocalDateTime;
/**
* FileName: MybatisPlusInsertTests
* Author: TP
* Description:
*/
@SpringBootTest
public class MybatisPlusInsertTests {
@Autowired
private UserMapper userMapper;
/**
* 插入1條數(shù)據(jù)壳坪,mp為我們提供了insert(T entity)方法
* 該方法插入一條記錄舶得,返回影響行數(shù)
* <p>
* 注意??:MP的默認(rèn)策略為:如果實(shí)體的某個(gè)屬性為null,那么新增和修改時(shí)爽蝴,會(huì)忽略null值字段
*/
@Test
void testInsert() {
User user = new User();
user.setName("向東");
user.setAge(58);
user.setManagerId(2);
user.setEmail("xb@163.com");
user.setCreateTime(LocalDateTime.now());
int rows = userMapper.insert(user);
System.out.println("影響記錄數(shù):" + rows);
System.out.println("新記錄的主鍵ID:" + user.getId());
}
}
MP為我們提供了insert(T entity)方法沐批,該方法插入一條記錄,返回影響行數(shù)蝎亚,MP的默認(rèn)策略為:如果實(shí)體的某個(gè)屬性為null九孩,那么新增和修改時(shí),會(huì)忽略null值字段发框,如果你想獲取新增的實(shí)體的ID躺彬,可以直接調(diào)用實(shí)體的getId方法獲取。
查詢
package com.tp.demo.mp;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.tp.demo.mp.entity.User;
import com.tp.demo.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* FileName: MybatisPlusSelectTests
* Author: TP
* Description: 查詢類測(cè)試
*/
@SpringBootTest
class MybatisPlusSelectTests {
@Autowired
private UserMapper userMapper;
// ========================= 非條件構(gòu)造器查詢 =========================
/**
* SELECT id,name,age,email,manager_id,create_time FROM user
*/
@Test
void testSelectList() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
/**
* SELECT id,name,age,email,manager_id,create_time FROM user WHERE id=?
*/
@Test
void testSelectById() {
User user = userMapper.selectById(1);
System.out.println(user);
}
/**
* SELECT id,name,age,email,manager_id,create_time FROM user WHERE id IN ( ? , ? )
*/
@Test
void testSelectBatchIds() {
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 3));
users.forEach(System.out::println);
}
/**
* SELECT id,name,age,email,manager_id,create_time FROM user WHERE manager_id = ? AND name = ?
*/
@Test
void testSelectByMap() {
Map<String, Object> queryMap = new HashMap<>();
queryMap.put("name", "向北");
queryMap.put("manager_id", 2); // 注意map的key為表的字段名缤底,value為要查的字段值
List<User> users = userMapper.selectByMap(queryMap);
users.forEach(System.out::println);
}
/**
* Map查詢顾患,查詢條件值為null的不會(huì)被忽略
* ==> Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE manager_id = ? AND name = ? AND email IS NULL
* ==> Parameters: 2(Integer), 向北(String)
*/
@Test
void testSelectByMap2() {
Map<String, Object> queryMap = new HashMap<>();
queryMap.put("name", "向北");
queryMap.put("manager_id", 2); // 注意map的key為表的字段名,value為要查的字段值
queryMap.put("email", null);
List<User> users = userMapper.selectByMap(queryMap);
users.forEach(System.out::println);
}
// ========================= Wrapper條件構(gòu)造器查詢 =========================
/**
* 通過(guò)條件構(gòu)造器查詢
* 名字為"張三"个唧,郵箱包含163,并且年齡<40
* Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE (name = ? AND email LIKE ? AND age < ?)
* Parameters: 張三(String), %163%(String), 40(Integer)
*/
@Test
void testSelectByWrapper() {
// MP提供了2種創(chuàng)建QueryWrapper的方法:
// QueryWrapper<User> queryWrapper = new QueryWrapper<>();
QueryWrapper<User> queryWrapper = Wrappers.query();
queryWrapper.eq("name", "張三").like("email", "163").lt("age", 40);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 名字中包含"雨"设预,并且年齡大于等于20且小于等于40徙歼,并且email不為空
* Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE (name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
* Parameters: %雨%(String), 20(Integer), 40(Integer)
*/
@Test
void testSelectByWrapper2() {
// MP提供了2種創(chuàng)建QueryWrapper的方法:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", "雨").between("age", 20, 40).isNotNull("email");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 名字為王姓或者年齡大于等于25,按照年齡降序排列鳖枕,年齡相同時(shí)按照id升序排列
* ==> Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE (name LIKE ? OR age >= ?) ORDER BY age DESC,id ASC
* ==> Parameters: 王%(String), 25(Integer)
*/
@Test
void testSelectByWrapper3() {
// MP提供了2種創(chuàng)建QueryWrapper的方法:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.likeRight("name", "王").or().ge("age", 25).orderByDesc("age").orderByAsc("id");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 名字為王姓魄梯,并且(年齡<40或郵箱為空)
* ==> Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE (name LIKE ? AND (age < ? OR email IS NOT NULL))
* ==> Parameters: 王%(String), 40(Integer)
*/
@Test
void testSelectByWrapper4() {
// MP提供了2種創(chuàng)建QueryWrapper的方法:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.likeRight("name", "王").and(qw -> qw.lt("age", 40).or().isNotNull("email"));
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 字為王姓,或者(年齡<40并且年齡>20并且郵箱不為空)
* ==> Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE (name LIKE ? OR (age < ? AND age > ? AND email IS NOT NULL))
* ==> Parameters: 王%(String), 40(Integer), 20(Integer)
*/
@Test
void testSelectByWrapper5() {
// MP提供了2種創(chuàng)建QueryWrapper的方法:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.likeRight("name", "王").
or(qw -> qw.lt("age", 40).gt("age", 20).isNotNull("email"));
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* (年齡<40或者郵箱不為空)并且姓名為王姓
* ==> Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE ((age < ? OR email IS NOT NULL) AND name LIKE ?)
* ==> Parameters: 40(Integer), 王%(String)
*/
@Test
void testSelectByWrapper7() {
// MP提供了2種創(chuàng)建QueryWrapper的方法:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.nested(wp -> wp.lt("age", 40).or().isNotNull("email")).likeRight("name", "王");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 年齡在(31宾符,32酿秸,34,45)中的
* ==> Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE (age IN (?,?,?,?))
* ==> Parameters: 31(Integer), 32(Integer), 34(Integer), 35(Integer)
*/
@Test
void testSelectByWrapper8() {
// MP提供了2種創(chuàng)建QueryWrapper的方法:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.in("age", Arrays.asList(31, 32, 34, 35));
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 返回滿足條件的其中一條記錄即可
* ==> Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE (age IN (?,?,?,?)) limit 1
* ==> Parameters: 31(Integer), 32(Integer), 34(Integer), 35(Integer)
*/
@Test
void testSelectByWrapper9() {
// MP提供了2種創(chuàng)建QueryWrapper的方法:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.in("age", Arrays.asList(31, 32, 34, 35)).last("limit 1"); // last會(huì)無(wú)視優(yōu)化魏烫,直接在sql后面拼接傳入的語(yǔ)句
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 默認(rèn)MP會(huì)查詢實(shí)體全部字段辣苏,如果我們只想查詢指定字段怎么辦呢肝箱?
* 查詢指定列方式一:指定要查詢的字段
* ==> Preparing: SELECT id,name,age FROM user WHERE (age < ?)
* ==> Parameters: 40(Integer)
*/
@Test
void testSelectByWrapper10() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id", "name", "age").lt("age", 40);
// .select(String... columns)可以放在前面,也可以放在后面稀蟋,例如下面注釋內(nèi)容
// queryWrapper.lt("age", 40).select("id", "name", "age");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 默認(rèn)MP會(huì)查詢實(shí)體全部字段煌张,如果我們只想查詢指定字段怎么辦呢?
* 查詢指定列方式二:動(dòng)態(tài)指定要查詢的字段退客,更有利于查詢實(shí)體類中多個(gè)字段骏融,不想像方式一那樣一個(gè)一個(gè)寫的情形
* ==> Preparing: SELECT id,name,age,manager_id FROM user
*/
@Test
void testSelectByWrapper11() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 排除create_time和email字段,即不查詢create_time和email字段
queryWrapper.select(User.class, info -> !info.getColumn().equals("create_time") && !info.getColumn().equals("email"));
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 關(guān)于condition
* 在QueryWrapper的各個(gè)查詢方法中萌狂,一般都會(huì)有重載的方法档玻,例如like
* <p>
* default Children like(R column, Object val) {
* return this.like(true, column, val);
* }
* <p>
* Children like(boolean condition, R column, Object val);
* <p>
* 其中有個(gè)重載的方法,前面需要傳一個(gè)boolean類型的condition茫藏,它的含義是:如果 condition的值為true時(shí)窃肠,則添加后面的查詢條件
* 例如我們做頁(yè)面的列表,用戶可輸入多個(gè)查詢條件刷允,有值的就添加上查詢條件
*/
@Test
void testSelectByWrapper12() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
boolean condition = (int) (Math.random() * 100) % 2 == 1;
System.out.println(condition);
queryWrapper
.lt("age", 40)
.eq(condition, "name", "張三"); //如果condition為false時(shí)冤留,不會(huì)添加查詢條件:and name = "張三"
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 我們可以通過(guò)一個(gè)實(shí)體構(gòu)造一個(gè)queryWrapper,MP默認(rèn)會(huì)將實(shí)體屬性中值不為空的作為查詢條件树灶,用and連接生成sql
* ==> Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE name=? AND age=?
* ==> Parameters: 向東(String), 58(Integer)
*/
@Test
void testSelectByEntity() {
User queryUser = new User();
queryUser.setName("向東");
queryUser.setAge(58);
QueryWrapper<User> queryWrapper = new QueryWrapper<>(queryUser);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 調(diào)用queryWrapper.allEq(params) 時(shí)纤怒,params中的null值會(huì)被翻譯成:字段名 is null
* 調(diào)用queryWrapper.allEq(params,false)時(shí),params中的null值會(huì)被忽略
*/
@Test
void testAllEq() {
// name = "向東" and age is null
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
Map<String, Object> params = new HashMap<>();
params.put("name", "向東");
params.put("age", null);
queryWrapper.allEq(params);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
// name = "向東"
QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
Map<String, Object> params2 = new HashMap<>();
params2.put("name", "向東");
params2.put("age", null);
queryWrapper2.allEq(params2, false);
List<User> users2 = userMapper.selectList(queryWrapper2);
users2.forEach(System.out::println);
}
/**
* 查詢返回一個(gè)map天通,map的key為數(shù)據(jù)庫(kù)中的字段
* 應(yīng)用場(chǎng)景1:當(dāng)我們查詢的字段不是所有字段泊窘,只是部分字段,如果我們用實(shí)體封裝像寒,那么實(shí)體中中未查詢的字段就為空或者默認(rèn)值烘豹,不優(yōu)雅,這個(gè)時(shí)候可以用map接收指定查詢的字段
* 應(yīng)用場(chǎng)景2:當(dāng)我們需要將數(shù)據(jù)庫(kù)中的字段進(jìn)行轉(zhuǎn)換诺祸,或者使用函數(shù)時(shí)携悯,這時(shí)候無(wú)法用實(shí)體封裝查詢結(jié)果,我們可以選擇使用map
*/
@Test
void testSelectMaps() {
// 應(yīng)用場(chǎng)景1
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "向東");
queryWrapper.select("name", "age"); // 只查詢部分字段
List<Map<String, Object>> result = userMapper.selectMaps(queryWrapper);
result.forEach(System.out::println);
//應(yīng)用場(chǎng)景2
QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
queryWrapper2
.select("avg(age) avg_age", "min(age) min_age", "max(age) max_age", "manager_id") // 計(jì)算查詢
.groupBy("manager_id").having("sum(age)<{0}", 50);
List<Map<String, Object>> result2 = userMapper.selectMaps(queryWrapper2);
result2.forEach(System.out::println);
}
/**
* 根據(jù)Wrapper查詢筷笨,查詢?nèi)坑涗? * 注意:只返回結(jié)果第一個(gè)字段的值
*/
@Test
void testSelectObjects() {
// 應(yīng)用場(chǎng)景1
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id", "name").lt("age", 60);
List<Object> objects = userMapper.selectObjs(queryWrapper); // 只會(huì)返回id憔鬼,不會(huì)返回name {1,2,3,4,5,6,7,8}
objects.forEach(System.out::println);
}
/**
* 根據(jù)查詢條件進(jìn)行統(tǒng)計(jì)總記錄數(shù)
*/
@Test
void testSelectCount() {
// 應(yīng)用場(chǎng)景1
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lt("age", 60);
Integer count = userMapper.selectCount(queryWrapper);
System.out.println(count);
}
/**
* 查詢1條結(jié)果,結(jié)果必須為1條或0條
* 如果數(shù)據(jù)庫(kù)存在多條會(huì)報(bào)錯(cuò)
*/
@Test
void testSelectOne() {
// 應(yīng)用場(chǎng)景1
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", 1);
User user = userMapper.selectOne(queryWrapper);
System.out.println(user);
}
// ========================= Lambda條件構(gòu)造器查詢 =========================
/**
* Lambda條件構(gòu)造器查詢能有效防止我們手寫數(shù)據(jù)庫(kù)字段寫錯(cuò)問(wèn)題
*/
@Test
void testSelectLambda1() {
// 創(chuàng)建Lambda條件構(gòu)造器的方式有3種:
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
LambdaQueryWrapper<User> lambdaQueryWrapper1 = Wrappers.lambdaQuery();
LambdaQueryWrapper lambdaQueryWrapper2 = new QueryWrapper<User>().lambda();
// User::getNamed代表要查詢name這個(gè)列胃夏,lambdaQueryWrapper的好處是避免手寫要查詢字段字符串轴或,如果手寫的也數(shù)據(jù)庫(kù)不一致造成報(bào)錯(cuò)問(wèn)題
lambdaQueryWrapper.eq(User::getName, "向東").lt(User::getAge, 80);
List<User> users = userMapper.selectList(lambdaQueryWrapper);
users.forEach(System.out::println);
}
@Test
void testSelectLambda2() {
// 創(chuàng)建Lambda條件構(gòu)造器的方式有3種:
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
LambdaQueryWrapper<User> lambdaQueryWrapper1 = Wrappers.lambdaQuery();
LambdaQueryWrapper lambdaQueryWrapper2 = new QueryWrapper<User>().lambda();
// where name like %王% and (age < 80 or email is not null)
lambdaQueryWrapper.likeRight(User::getName, "王").and(lqw -> lqw.lt(User::getAge, 40).or().isNotNull(User::getEmail));
List<User> users = userMapper.selectList(lambdaQueryWrapper);
users.forEach(System.out::println);
}
/**
* LambdaQueryChainWrapper,這個(gè)可以再次簡(jiǎn)化寫法仰禀,可以直接調(diào)用.list() 或者 .one() 返回查詢結(jié)果
*/
@Test
void testSelectLambdaQueryChainWrapper() {
// 創(chuàng)建Lambda條件構(gòu)造器的方式有3種:
LambdaQueryChainWrapper<User> lambdaQueryChainWrapper = new LambdaQueryChainWrapper<>(userMapper);
List<User> users = lambdaQueryChainWrapper
.likeRight(User::getName, "王")
.and(lqw -> lqw.lt(User::getAge, 40).or().isNotNull(User::getEmail))
.list(); // 可以直接調(diào)用.list() 或者 .one() 返回查詢結(jié)果
users.forEach(System.out::println);
}
}
修改
package com.tp.demo.mp;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.tp.demo.mp.entity.User;
import com.tp.demo.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* FileName: MybatisPlusUpdateTests
* Author: TP
* Description:
*/
@SpringBootTest
class MybatisPlusUpdateTests {
@Autowired
private UserMapper userMapper;
/**
* UpdateById
* 根據(jù)主鍵ID修改實(shí)體信息的方法
* 此更新會(huì)忽略實(shí)體null值照雁,不會(huì)更新實(shí)體中屬性值為null對(duì)應(yīng)的字段
*/
@Test
void testUpdateById() {
User user = new User();
user.setId(8);
user.setEmail("xd@163.com");
userMapper.updateById(user);
}
/**
* 利用UpdateWrapper更新實(shí)體>>>>空參構(gòu)造器:UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
* UpdateWrapper的條件會(huì)出現(xiàn)在where條件中
* 實(shí)體不為空的信息是要更新的字段
*/
@Test
void testUpdateByWrapper() {
// UpdateWrapper的條件會(huì)出現(xiàn)在where條件中
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("name", "李藝偉");
updateWrapper.eq("age", 28);
// 實(shí)體不為空的信息是要更新的字段
User user = new User();
user.setEmail("lyw@126.com");
user.setManagerId(1);
// 返回影響行數(shù)
int rows = userMapper.update(user, updateWrapper);
System.out.println("影響行數(shù):" + rows);
}
/**
* 利用UpdateWrapper更新實(shí)體>>>>帶參構(gòu)造器:UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(whereUser);
* 這時(shí)候updateWrapper中會(huì)將whereUser這個(gè)實(shí)體中不為空的屬性設(shè)置為where查詢條件
* 注意:這個(gè)時(shí)候whereUser實(shí)體的查詢條件和后續(xù)updateWrapper調(diào)用查詢方法時(shí)指定的查詢條件會(huì)同時(shí)生效,如果存在相同查詢條件答恶,查詢條件會(huì)出現(xiàn)2次
*/
@Test
void testUpdateByWrapper2() {
// 通過(guò)實(shí)體構(gòu)造查詢條件
User whereUser = new User();
whereUser.setName("李藝偉");
whereUser.setAge(28);
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(whereUser);
// updateWrapper.eq("manager_id", 1); // 可以繼續(xù)添加查詢條件
// 實(shí)體不為空的信息是要更新的字段
User user = new User();
user.setEmail("lyw@qq.com");
user.setManagerId(2);
// 返回影響行數(shù)
int rows = userMapper.update(user, updateWrapper);
System.out.println("影響行數(shù):" + rows);
}
/**
* 利用UpdateWrapper更新實(shí)體>>>>帶參構(gòu)造器:UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(whereUser);
* 如果我們更新的字段很少饺蚊,例如實(shí)體中我們只更新1萍诱、2個(gè)字段,如果像上面的更新還需要?jiǎng)?chuàng)建一個(gè)對(duì)象卸勺,這樣有點(diǎn)不優(yōu)雅
* 又或者我們的需求是想把某個(gè)字段設(shè)置為null
* 這時(shí)候我們可以使用UpdateWrapper的set方法砂沛,指定設(shè)置數(shù)據(jù)庫(kù)表中具體哪個(gè)字段設(shè)置為什么值
*/
@Test
void testUpdateByWrapper3() {
// 通過(guò)實(shí)體構(gòu)造查詢條件
User whereUser = new User();
whereUser.setName("李藝偉");
whereUser.setAge(28);
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(whereUser);
updateWrapper.set("age", 29).set("email", null);
// 返回影響行數(shù)
int rows = userMapper.update(null, updateWrapper);
System.out.println("影響行數(shù):" + rows);
}
/**
* UpdateWrapper同樣支持Lambda形式,用法類似LambdaQueryWrapper
*/
@Test
void testUpdateByWrapperLambda() {
// 構(gòu)造LambdaUpdateWrapper
LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(User::getName, "李藝偉").set(User::getAge, 30).set(User::getEmail, "lyw@163.com");
// 返回影響行數(shù)
int rows = userMapper.update(null, lambdaUpdateWrapper);
System.out.println("影響行數(shù):" + rows);
}
/**
* 同理曙求,UpdateWrapper同樣支持LambdaChain形式
* 用法類似LambdaQueryChainWrapper
* 但其返回值不是影響行數(shù)碍庵,而是boolean值,標(biāo)識(shí)更新成功或失敗
*/
@Test
void testUpdateByWrapperLambdaChain() {
// 構(gòu)造LambdaUpdateWrapper
LambdaUpdateChainWrapper<User> chainWrapper = new LambdaUpdateChainWrapper<>(userMapper);
boolean result = chainWrapper
.eq(User::getName, "李藝偉") // 設(shè)置查詢條件
.set(User::getAge, 31).set(User::getEmail, "lyw@chain.com") //設(shè)置要更新的內(nèi)容
.update(); //需要調(diào)用update()悟狱,執(zhí)行更新
System.out.println("更新是否成功:" + result);
}
}
刪除
package com.tp.demo.mp;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tp.demo.mp.entity.User;
import com.tp.demo.mp.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* FileName: MybatisPlusDeleteTests
* Author: TP
* Description:
*/
@SpringBootTest
class MybatisPlusDeleteTests {
@Autowired
private UserMapper userMapper;
/**
* 根據(jù)ID單個(gè)刪除
*/
@Test
void testDeleteById() {
int rows = userMapper.deleteById(8);
System.out.println("影響記錄數(shù):" + rows);
}
/**
* 根據(jù)ID批量刪除
*/
@Test
void testDeleteBatchIds() {
int rows = userMapper.deleteBatchIds(Arrays.asList(9, 10));
System.out.println("影響記錄數(shù):" + rows);
}
/**
* 根據(jù)Map静浴,map中的元素會(huì)作為查詢條件且等值and連接
*/
@Test
void testDeleteByMap() {
Map<String, Object> map = new HashMap<>();
map.put("name", "向東");
map.put("age", 31);
map.put("manager_id", null);
int rows = userMapper.deleteByMap(map);
System.out.println("影響記錄數(shù):" + rows);
}
/**
* 根據(jù)QueryWrapper條件構(gòu)造器刪除
*/
@Test
void testDeleteByWrapper() {
QueryWrapper<User> queryWrapper = Wrappers.query();
queryWrapper.eq("name", "向東");
queryWrapper.eq("age", "31");
int rows = userMapper.delete(queryWrapper);
System.out.println("影響記錄數(shù):" + rows);
}
/**
* 根據(jù)QueryWrapper條件構(gòu)造器,通過(guò)指定一個(gè)實(shí)體刪除
*/
@Test
void testDeleteByWrapper2() {
User user = new User();
user.setName("向東");
user.setAge(31);
QueryWrapper<User> queryWrapper = Wrappers.query(user);
int rows = userMapper.delete(queryWrapper);
System.out.println("影響記錄數(shù):" + rows);
}
/**
* 根據(jù)LambdaQueryWrapper條件構(gòu)造器刪除
*/
@Test
void testDeleteByLambdaQueryWrapper() {
LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
// DELETE FROM user WHERE (name = ? OR age >= ?)
lambdaQueryWrapper.eq(User::getName, "向東").or().ge(User::getAge, 60);
int rows = userMapper.delete(lambdaQueryWrapper);
System.out.println("影響記錄數(shù):" + rows);
}
/**
* 根據(jù)LambdaQueryWrapper條件構(gòu)造器挤渐,通過(guò)指定一個(gè)實(shí)體刪除
*/
@Test
void testDeleteByLambdaQueryWrapper2() {
User user = new User();
user.setName("向東");
user.setAge(50);
LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery(user);
int rows = userMapper.delete(lambdaQueryWrapper);
System.out.println("影響記錄數(shù):" + rows);
}
}
Mybatis-Plus分頁(yè)
Mybatis-Plus為我們提供了非常方便的分頁(yè)插件苹享,用法:
package com.tp.demo.mp.config;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* FileName: MybatisPlusPageConfig
* Author: TP
* Description: 使用mybatisPlus的分頁(yè)插件
* 只需要提供一個(gè)PaginationInnerInterceptor交給Spring管理即可
*/
@Configuration
public class MybatisPlusPageConfig {
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor(){
return new PaginationInnerInterceptor();
}
}
測(cè)試:
package com.tp.demo.mp;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tp.demo.mp.entity.User;
import com.tp.demo.mp.mapper.UserMapper;
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;
/**
* FileName: MybatisPlusPageTests
* Author: TP
* Description: mybatisPlus分頁(yè)測(cè)試
*/
@SpringBootTest
class MybatisPlusPageTests {
@Autowired
private UserMapper userMapper;
/**
* 分頁(yè),結(jié)果采用實(shí)體封裝
*/
@Test
void testPage1() {
Page<User> userPage = new Page<>(1, 10); //當(dāng)前頁(yè)為第1頁(yè)浴麻,每頁(yè)顯示10條
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lt("age", 80);
Page<User> pageResult = userMapper.selectPage(userPage, queryWrapper);
System.out.println("總頁(yè)數(shù):" + pageResult.getPages());
System.out.println("總記錄數(shù):" + pageResult.getTotal());
List<User> users = pageResult.getRecords();
users.forEach(System.out::println);
}
/**
* 分頁(yè)得问,結(jié)果采用Map封裝,key為列名或者列別名软免,value為值
*/
@Test
void testPage2() {
Page<Map<String, Object>> userPage = new Page<>(1, 10); //當(dāng)前頁(yè)為第1頁(yè)宫纬,每頁(yè)顯示10條
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lt("age", 80).select("name", "age");
Page<Map<String, Object>> pageResult = userMapper.selectMapsPage(userPage, queryWrapper);
System.out.println("總頁(yè)數(shù):" + pageResult.getPages());
System.out.println("總記錄數(shù):" + pageResult.getTotal());
List<Map<String, Object>> users = pageResult.getRecords();
users.forEach(System.out::println);
}
}