该文章为学习笔记,在线文档
https://b11et3un53m.feishu.cn/wiki/FYNkwb1i6i0qwCk7lF2caEq5nRe
一、快速入门
1、使用的基本步骤
(1)引入MybatisPlus
依赖,代替 Mybatis
依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
(2)定义 Mapper
接口并继承 BaseMapper
public interface UserMapper extends BaseMapper<User> {
}
(3)在实体类上添加注解声明 表信息
- 详情见《常见注解》
(4)在application.yml中根据需要添加配置
- 详情见《常见配置》
2、常见注解
MybatisPlus
通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。
符合约定的如下解析
- 默认以类名驼峰转下划线作为表名
- 默认以名为id的字段作为主键
- 默认以变量名驼峰转下划线作为表的字段名
不符合约定的添加注解
MybatisPlus
中比较常用的几个注解如下:
@TableName
用来指定表名及全局配置@TableId
用来指定表中的主键字段信息及相关配置@TableField
用来指定表中的普通字段信息及相关配置
@TableName("user")
public class User {
@TableId(value="id", type=IdType.AUTO)
private Long id;
private String name;
private Integer age;
@TableField("isMarried")
private Boolean isMarried;
@TableField("concat")
private String concat;
}
IdType
支持的常见类型有:
AUTO
数据库 ID 自增INPUT
insert 前自行 set 主键值ASSIGN_ID
分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0)
,使用接口IdentifierGenerator
的方法nextId
(默认实现类为DefaultIdentifierGenerator雪花算法)
@TableId(value="id", type=IdType.AUTO)
使用TableField
的常见场景:
- 成员变量名与数据库字段名不一致
- 成员变量名以is开头,且是布尔值
- 成员变量名与数据库关键字冲突
- 成员变量不是数据库字段
// 成员变量名与数据库字段名不一致
@TableField("username")
private String name;
// 成员变量名义is开头,且是布尔值
@TableField("is_married")
private Boolean isMarried;
// 成员变量名与数据库关键字冲突
@TableField("`order`")
private Integer order;
// 成员变量不是数据库字段
@TableField(exist = false)
private String address;
3、常见配置
MyBatisPlus
的配置项继承了MyBatis
原生配置和一些自己特有的配置。例如:
mybatis-plus:
type-aliases-package: com.itheima.mp.domain.po # 别名扫描包
mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,默认值
configuration:
map-underscore-to-camel-case: true # 是否开启下划线和驼峰的映射
cache-enabled: false # 是否开启二级缓存
global-config:
db-config:
id-type: assign_id # id为雪花算法生成
update-strategy: not_null # 更新策略:只更新非空字段
二、核心功能
1、条件构造器
QueryWrapper
和LambdaQueryWrapper
通常用来构建select
、delete
、update
的where
条件部分UpdateWrapper
和LambdaUpdateWrapper
通常只在set
语句比较特殊才使用- 尽量使用
LambdaQueryWrapper
和LambdaUpdateWrapper
,避免硬编码
(1)QueryWrapper
- 无论是修改、删除、查询,都可以使用
QueryWrapper
来构建查询条件。 - 查询出名字中带o的,存款大于等于1000元的人。代码如下:
@Test
void testQueryWrapper() {
// 1.构建查询条件 where name like "%o%" AND balance >= 1000
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.select("id", "username", "info", "balance")
.like("username", "o")
.ge("balance", 1000);
// 2.查询数据
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
- 更新用户名为jack的用户的余额为2000,代码如下:
@Test
void testUpdateByQueryWrapper() {
// 1.构建查询条件 where name = "Jack"
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.eq("username", "Jack");
// 2.更新数据,user中非null字段都会作为set语句
User user = new User();
user.setBalance(2000);
userMapper.update(user, wrapper);
}
(2)UpdateWrapper
- 基于
BaseMapper
中的update
方法更新时只能直接赋值,对于一些复杂的需求就难以实现。 - 例如:更新id为1,2,4的用户的余额,扣200,对应的SQL应该是:
UPDATE user SET balance = balance - 200 WHERE id in (1, 2, 4)
- SET的赋值结果是基于字段现有值的,这个时候就要利用
UpdateWrapper
中的setSql
功能了:
@Test
void testUpdateWrapper() {
List<Long> ids = List.of(1L, 2L, 4L);
// 1.生成SQL
UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
.setSql("balance = balance - 200") // SET balance = balance - 200
.in("id", ids); // WHERE id in (1, 2, 4)
// 2.更新,注意第一个参数可以给null,也就是不填更新字段和数据,
// 而是基于UpdateWrapper中的setSQL来更新
userMapper.update(null, wrapper);
}
(3)LambdaQueryWrapper
- 无论是
QueryWrapper
还是UpdateWrapper
在构造条件的时候都需要写死字段名称,会出现字符串魔法值。这在编程规范中显然是不推荐的。 - 其中一种办法是基于变量的
gettter
方法结合反射技术。 - 因此我们只要将条件对应的字段的
getter
方法传递给MybatisPlus
,它就能计算出对应的变量名了。 - 而传递方法可以使用JDK8中的方法引用和Lambda表达式。
- 因此
MybatisPlus
又提供了一套基于Lambda
的Wrapper
,包含两个: LambdaQueryWrapper
和LambdaUpdateWrapper
- 分别对应
QueryWrapper
和UpdateWrapper
- 查询出名字中带o的,存款大于等于1000元的人。代码如下:
@Test
void testLambdaQueryWrapper() {
// 1.构建条件 WHERE username LIKE "%o%" AND balance >= 1000
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.lambda()
.select(User::getId, User::getUsername, User::getInfo, User::getBalance)
.like(User::getUsername, "o")
.ge(User::getBalance, 1000);
// 2.查询
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
2、自定义SQL
- 我们可以利用
MyBatisPlus
的Wrapper
来构建复杂的Where
条件 - 然后自己定义
SQL
语句中剩下的部分
(1)基于Wrapper
构建where
条件
List<Long> ids = List.of(1L, 2L, 4L);
int amount = 200;
// 1.构建条件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
.in(User::getId, ids);
// 2.自定义SQL方法调用
userMapper.updateBalanceByIds(wrapper, amount);
(2)在mapper
方法参数中用Param
注解声明 wrapper
变量名称,必须是 ew
void updateBalanceByIds(@Param("ew") LambdaQueryWrapper<User> wrapper, @Param("amount") int amount);
(3)自定义SQL,并使用 Wrapper
条件
UserMapper.xml
<update id="updateBalanceByIds">
UPDATE tb_user SET balance = balance - #{amount} ${ew.customSqlSegment}
</update>
- 在
mapper
方法参数前添加Select
注解 UserMapper.java
@Select("UPDATE user SET balance = balance - #{money} ${ew.customSqlSegment}")
3、Service接口
(1)使用流程
- 自定义
Service
接口继承IService
接口
public interface IUserService extends IService<User> {
}
- 自定义
Service
实现类,实现自定义接口并继承ServiceImpl
类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}
(2)接口实现
实现以下接口
- 引入依赖
swagger
、web
<!--swagger-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
application.yaml
中配置swagger
信息
knife4j:
enable: true
openapi:
title: 用户管理接口文档
description: "用户管理接口文档"
email: zhanghuyi@itcast.cn
concat: 虎哥
url: https://www.itcast.cn
version: v1.0.0
group:
default:
group-name: default
api-rule: package
api-rule-resources:
- com.itheima.mp.controller
- 实体:
UserFormDTO
:代表新增时的用户表单
package com.itheima.mp.domain.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(description = "用户表单实体")
public class UserFormDTO {
@ApiModelProperty("id")
private Long id;
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("密码")
private String password;
@ApiModelProperty("注册手机号")
private String phone;
@ApiModelProperty("详细信息,JSON风格")
private String info;
@ApiModelProperty("账户余额")
private Integer balance;
}
- 实体:
UserVO
:代表查询的返回结果
package com.itheima.mp.domain.vo;
import io.swagger.annotations.ApiModel;
import