MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
支持数据库
mysql 、mariadb 、oracle 、db2 、h2 、hsql 、sqlite 、postgresql 、sqlserver 、presto 、Gauss 、Firebird
Phoenix 、clickhouse 、Sybase ASE 、 OceanBase 、达梦数据库 、虚谷数据库 、人大金仓数据库 、南大通用数据库 、
框架结构
快速开始
以springboot项目为例
引入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驱动 -->
<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> <!-- 标识依赖不会传递 -->
</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>
配置数据库连接信息
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
创建一个数据库表
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 '直属上级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;
项目中创建实体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;
/** 直属上级ID */
private Integer managerId;
/** 创建时间 */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") //此注解用来接收字符串类型的参数封装成LocalDateTime类型
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") //此注解将date类型数据转成字符串响应出去
private LocalDateTime createTime;
/** 对于数据库中没有的字段,如果我们不处理,在新增或修改的时候会出现错误,mp为我们提供了注解@TableField解决此类问题 */
@TableField(exist = false) // exist = false标识数据库没有此字段,告诉mp映射时忽略此字段,防止出现错误,默认为true
List<Integer> roleIds;
}
注意:对于数据库中没有的字段,如果我们不做特殊处理,我们在操作数据库时MP会给我们自动进行映射,但是因为数据库中并没有这个字段,这样就会报错:
org.springframework.jdbc.BadSqlGrammarException:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column 'role_ids' in 'field list'
针对这种情形,我们可以使用MP提供的注解@TableField(exist = false)
来表明某个字段不是数据库的字段,其中exist表示是否存在,默认为true
创建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: 用户服务Mapper
*/
public interface UserMapper extends BaseMapper<User> {
}
接下来就可以测试啦,实际开发中我们应该写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条数据,mp为我们提供了insert(T entity)方法
* 该方法插入一条记录,返回影响行数
* <p>
* 注意⚠️:MP的默认策略为:如果实体的某个属性为null,那么新增和修改时,会忽略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("影响记录数:" + rows);
System.out.println("新记录的主键ID:" + user.getId());
}
}
MP为我们提供了insert(T entity)方法,该方法插入一条记录,返回影响行数,MP的默认策略为:如果实体的某个属性为null,那么新增和修改时,会忽略null值字段,如果你想获取新增的实体的ID,可以直接调用实体的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: 查询类测试
*/
@SpringBootTest
class MybatisPlusSelectTests {
@Autowired
private UserMapper userMapper;
// ========================= 非条件构造器查询 =========================
/**
* 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的不会被忽略
* ==> 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条件构造器查询 =========================
/**
* 通过条件构造器查询
* 名字为"张三",邮箱包含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种创建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种创建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,按照年龄降序排列,年龄相同时按照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种创建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种创建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种创建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种创建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种创建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种创建QueryWrapper的方法:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.in("age", Arrays.asList(31, 32, 34, 35)).last("limit 1"); // last会无视优化,直接在sql后面拼接传入的语句
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 默认MP会查询实体全部字段,如果我们只想查询指定字段怎么办呢?
* 查询指定列方式一:指定要查询的字段
* ==> 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)可以放在前面,也可以放在后面,例如下面注释内容
// queryWrapper.lt("age", 40).select("id", "name", "age");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 默认MP会查询实体全部字段,如果我们只想查询指定字段怎么办呢?
* 查询指定列方式二:动态指定要查询的字段,更有利于查询实体类中多个字段,不想像方式一那样一个一个写的情形
* ==> 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);
}
/**
* 关于condition
* 在QueryWrapper的各个查询方法中,一般都会有重载的方法,例如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>
* 其中有个重载的方法,前面需要传一个boolean类型的condition,它的含义是:如果 condition的值为true时,则添加后面的查询条件
* 例如我们做页面的列表,用户可输入多个查询条件,有值的就添加上查询条件
*/
@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时,不会添加查询条件:and name = "张三"
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
/**
* 我们可以通过一个实体构造一个queryWrapper,MP默认会将实体属性中值不为空的作为查询条件,用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);
}
/**
* 调用queryWrapper.allEq(params) 时,params中的null值会被翻译成:字段名 is null
* 调用queryWrapper.allEq(params,false)时,params中的null值会被忽略
*/
@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);
}
/**
* 查询返回一个map,map的key为数据库中的字段
* 应用场景1:当我们查询的字段不是所有字段,只是部分字段,如果我们用实体封装,那么实体中中未查询的字段就为空或者默认值,不优雅,这个时候可以用map接收指定查询的字段
* 应用场景2:当我们需要将数据库中的字段进行转换,或者使用函数时,这时候无法用实体封装查询结果,我们可以选择使用map
*/
@Test
void testSelectMaps() {
// 应用场景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);
//应用场景2
QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
queryWrapper2
.select("avg(age) avg_age", "min(age) min_age", "max(age) max_age", "manager_id") // 计算查询
.groupBy("manager_id").having("sum(age)<{0}", 50);
List<Map<String, Object>> result2 = userMapper.selectMaps(queryWrapper2);
result2.forEach(System.out::println);
}
/**
* 根据Wrapper查询,查询全部记录
* 注意:只返回结果第一个字段的值
*/
@Test
void testSelectObjects() {
// 应用场景1
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id", "name").lt("age", 60);
List<Object> objects = userMapper.selectObjs(queryWrapper); // 只会返回id,不会返回name {1,2,3,4,5,6,7,8}
objects.forEach(System.out::println);
}
/**
* 根据查询条件进行统计总记录数
*/
@Test
void testSelectCount() {
// 应用场景1
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lt("age", 60);
Integer count = userMapper.selectCount(queryWrapper);
System.out.println(count);
}
/**
* 查询1条结果,结果必须为1条或0条
* 如果数据库存在多条会报错
*/
@Test
void testSelectOne() {
// 应用场景1
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("id", 1);
User user = userMapper.selectOne(queryWrapper);
System.out.println(user);
}
// ========================= Lambda条件构造器查询 =========================
/**
* Lambda条件构造器查询能有效防止我们手写数据库字段写错问题
*/
@Test
void testSelectLambda1() {
// 创建Lambda条件构造器的方式有3种:
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
LambdaQueryWrapper<User> lambdaQueryWrapper1 = Wrappers.lambdaQuery();
LambdaQueryWrapper lambdaQueryWrapper2 = new QueryWrapper<User>().lambda();
// User::getNamed代表要查询name这个列,lambdaQueryWrapper的好处是避免手写要查询字段字符串,如果手写的也数据库不一致造成报错问题
lambdaQueryWrapper.eq(User::getName, "向东").lt(User::getAge, 80);
List<User> users = userMapper.selectList(lambdaQueryWrapper);
users.forEach(System.out::println);
}
@Test
void testSelectLambda2() {
// 创建Lambda条件构造器的方式有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,这个可以再次简化写法,可以直接调用.list() 或者 .one() 返回查询结果
*/
@Test
void testSelectLambdaQueryChainWrapper() {
// 创建Lambda条件构造器的方式有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(); // 可以直接调用.list() 或者 .one() 返回查询结果
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
* 根据主键ID修改实体信息的方法
* 此更新会忽略实体null值,不会更新实体中属性值为null对应的字段
*/
@Test
void testUpdateById() {
User user = new User();
user.setId(8);
user.setEmail("xd@163.com");
userMapper.updateById(user);
}
/**
* 利用UpdateWrapper更新实体>>>>空参构造器:UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
* UpdateWrapper的条件会出现在where条件中
* 实体不为空的信息是要更新的字段
*/
@Test
void testUpdateByWrapper() {
// UpdateWrapper的条件会出现在where条件中
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("name", "李艺伟");
updateWrapper.eq("age", 28);
// 实体不为空的信息是要更新的字段
User user = new User();
user.setEmail("lyw@126.com");
user.setManagerId(1);
// 返回影响行数
int rows = userMapper.update(user, updateWrapper);
System.out.println("影响行数:" + rows);
}
/**
* 利用UpdateWrapper更新实体>>>>带参构造器:UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(whereUser);
* 这时候updateWrapper中会将whereUser这个实体中不为空的属性设置为where查询条件
* 注意:这个时候whereUser实体的查询条件和后续updateWrapper调用查询方法时指定的查询条件会同时生效,如果存在相同查询条件,查询条件会出现2次
*/
@Test
void testUpdateByWrapper2() {
// 通过实体构造查询条件
User whereUser = new User();
whereUser.setName("李艺伟");
whereUser.setAge(28);
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(whereUser);
// updateWrapper.eq("manager_id", 1); // 可以继续添加查询条件
// 实体不为空的信息是要更新的字段
User user = new User();
user.setEmail("lyw@qq.com");
user.setManagerId(2);
// 返回影响行数
int rows = userMapper.update(user, updateWrapper);
System.out.println("影响行数:" + rows);
}
/**
* 利用UpdateWrapper更新实体>>>>带参构造器:UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(whereUser);
* 如果我们更新的字段很少,例如实体中我们只更新1、2个字段,如果像上面的更新还需要创建一个对象,这样有点不优雅
* 又或者我们的需求是想把某个字段设置为null
* 这时候我们可以使用UpdateWrapper的set方法,指定设置数据库表中具体哪个字段设置为什么值
*/
@Test
void testUpdateByWrapper3() {
// 通过实体构造查询条件
User whereUser = new User();
whereUser.setName("李艺伟");
whereUser.setAge(28);
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>(whereUser);
updateWrapper.set("age", 29).set("email", null);
// 返回影响行数
int rows = userMapper.update(null, updateWrapper);
System.out.println("影响行数:" + rows);
}
/**
* UpdateWrapper同样支持Lambda形式,用法类似LambdaQueryWrapper
*/
@Test
void testUpdateByWrapperLambda() {
// 构造LambdaUpdateWrapper
LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(User::getName, "李艺伟").set(User::getAge, 30).set(User::getEmail, "lyw@163.com");
// 返回影响行数
int rows = userMapper.update(null, lambdaUpdateWrapper);
System.out.println("影响行数:" + rows);
}
/**
* 同理,UpdateWrapper同样支持LambdaChain形式
* 用法类似LambdaQueryChainWrapper
* 但其返回值不是影响行数,而是boolean值,标识更新成功或失败
*/
@Test
void testUpdateByWrapperLambdaChain() {
// 构造LambdaUpdateWrapper
LambdaUpdateChainWrapper<User> chainWrapper = new LambdaUpdateChainWrapper<>(userMapper);
boolean result = chainWrapper
.eq(User::getName, "李艺伟") // 设置查询条件
.set(User::getAge, 31).set(User::getEmail, "lyw@chain.com") //设置要更新的内容
.update(); //需要调用update(),执行更新
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;
/**
* 根据ID单个删除
*/
@Test
void testDeleteById() {
int rows = userMapper.deleteById(8);
System.out.println("影响记录数:" + rows);
}
/**
* 根据ID批量删除
*/
@Test
void testDeleteBatchIds() {
int rows = userMapper.deleteBatchIds(Arrays.asList(9, 10));
System.out.println("影响记录数:" + rows);
}
/**
* 根据Map,map中的元素会作为查询条件且等值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("影响记录数:" + rows);
}
/**
* 根据QueryWrapper条件构造器删除
*/
@Test
void testDeleteByWrapper() {
QueryWrapper<User> queryWrapper = Wrappers.query();
queryWrapper.eq("name", "向东");
queryWrapper.eq("age", "31");
int rows = userMapper.delete(queryWrapper);
System.out.println("影响记录数:" + rows);
}
/**
* 根据QueryWrapper条件构造器,通过指定一个实体删除
*/
@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("影响记录数:" + rows);
}
/**
* 根据LambdaQueryWrapper条件构造器删除
*/
@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("影响记录数:" + rows);
}
/**
* 根据LambdaQueryWrapper条件构造器,通过指定一个实体删除
*/
@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("影响记录数:" + rows);
}
}
Mybatis-Plus分页
Mybatis-Plus为我们提供了非常方便的分页插件,用法:
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的分页插件
* 只需要提供一个PaginationInnerInterceptor交给Spring管理即可
*/
@Configuration
public class MybatisPlusPageConfig {
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor(){
return new PaginationInnerInterceptor();
}
}
测试:
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分页测试
*/
@SpringBootTest
class MybatisPlusPageTests {
@Autowired
private UserMapper userMapper;
/**
* 分页,结果采用实体封装
*/
@Test
void testPage1() {
Page<User> userPage = new Page<>(1, 10); //当前页为第1页,每页显示10条
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lt("age", 80);
Page<User> pageResult = userMapper.selectPage(userPage, queryWrapper);
System.out.println("总页数:" + pageResult.getPages());
System.out.println("总记录数:" + pageResult.getTotal());
List<User> users = pageResult.getRecords();
users.forEach(System.out::println);
}
/**
* 分页,结果采用Map封装,key为列名或者列别名,value为值
*/
@Test
void testPage2() {
Page<Map<String, Object>> userPage = new Page<>(1, 10); //当前页为第1页,每页显示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("总页数:" + pageResult.getPages());
System.out.println("总记录数:" + pageResult.getTotal());
List<Map<String, Object>> users = pageResult.getRecords();
users.forEach(System.out::println);
}
}