官网地址:MyBatis-Plus🚀为简化开发而生
快速上手
一、引入依赖 && 配置
SpringBoot2
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>SpringBoot3
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>MySQL
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>配置数据库,application.yml 文件:
# 数据库连接配置
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver二、编码
创建实体类 UserInfo:
实体类的属性名与表中的字段名一一对应
import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {
private Integer id;
private String username;
private String password;
private Integer age;
private Integer gender;
private String phone;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}编写 Mapper 接口类:
MybatisPlus 提供了一个基础的 BaseMapper 接口,已经实现了单表的 CRUD,我们自定义的 Mapper只需要继承这个 BaseMapper,就无需自己实现单表 CRUD了,如下所示:
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
也可以在启动类上添加 @MapperScan,扫描 Mapper 文件夹,二选一即可。
复杂操作
一、常见注解
在上面的程序中,MyBatis 是如何知道,我们要操作的是哪张表,表里有哪些字段呢?
我们来看下咱们 Mapper 的代码:
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}UserInfoMapper 在继承 BaseMapper 时,指定了一个泛型,这个 UserInfo 就是与数据库表相对应的实体类。
MyBatis-Plus 会根据这个实体类来推断表的信息。
默认情况下:
-
表名: 实体类的驼峰表示法 -> 蛇形表示法作为表名。比如
UserInfo->user_info -
字段: 实体类的属性名 -> 蛇形表示法作为字段名。比如
deleteFlag->delete_flag -
主键: 默认为
id
那如果实体类和数据库不是按照上述规则定义的呢?MyBatis-Plus 也给我们提供了一下注解,让我们标识表的信息。
1. @TableName
通过 @TableName 来标识实体类对应的表:
@Data
@TableName("user_info")
public class Userinfo {
private Integer id;
private String username;
private String password;
private Integer age;
private Integer gender;
private String phone;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}2. @TableField
通过 @TableField 来标识对应的字段名:
@Data
public class Userinfo {
private Integer id;
private String username;
private String password;
private Integer age;
private Integer gender;
private String phone;
@TableField("delete_flag") // 定义和数据库字段名相同
private Integer deleteflag;
private Date createTime;
private Date updateTime;
}3. @TableId
通过 @TableId 来指定对应的主键:
@Data
public class Userinfo {
@TableId("id", type = IdType.AUTO)
private Integer userId;
private String username;
private String password;
private Integer age;
private Integer gender;
private String phone;
private Integer deleteflag;
private Date createTime;
private Date updateTime;
}-
如果属性名和字段名一致,直接加
@TableId注解就可以 -
如果属性名和字段名不一致,需要在
@TableId指明对应的字段名
常见的
IdType类型如下所示:
AUTO
数据库自增 ID(通常配合
MySQL的AUTO_INCREMENT)。由数据库生成,插入时不需要自己赋值。
NONE(默认值)
- 不设置主键类型,MyBatis-Plus 不会自动处理,走数据库自身策略。
INPUT
- 主键由你自己传入(手动 set)。
ASSIGN_ID
MyBatis-Plus 内置的全局唯一 ID 生成器(类似雪花算法),适合分布式系统。
插入前自动生成。
ASSIGN_UUID
- 自动生成一个
UUID字符串作为主键。
二、打印日志
在配置文件中添加如下内容:
mybatis-plus:
configuration: # 配置打印 MyBatis日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl三、条件构造器
MyBatis-Plus 提供了一套强大的条件构造器 Wrapper,用于构建复杂的数据库查询条件 。Wrapper 类允许开发者以链式调用的方式构造查询条件,无需编写繁琐的 SQL 语句,从而提高开发效率并减少 SQL 注入的风险。
以下是主要的 Wrapper 类及其功能:
-
AbstractWrapper:这是一个抽象基类,提供了所有Wrapper类共有的方法和属性。 -
QueryWrapper:用于构造查询条件,在AbstractWrapper的基础上拓展了一个select方法,允许指定查询字段。 -
UpdateWrapper:用于构造更新条件,可以在更新数据时指定条件。 -
LambdaQueryWrapper:基于Lambda表达式的查询条件构造器,它通过Lambda表达式来引用实体类的属性,从而避免了硬编码字段名。 -
LambdaUpdateWrapper:基于Lambda表达式的更新条件构造器,它允许你使用Lambda表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。
1. QueryWrapper
查询
完成下述SQL查询:
SELECT id,username,password,age FROM user_info WHERE age = 18 AND username LIKE "%min%"测试代码:
@Test
void testQueryWrapper(){
QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>()
.select("id","username","password","age")
.eq("age",18)
.like("username", "min");
List<UserInfo> userInfos = userInfoMapper.selectList(userInfoQueryWrapper);
userInfos.forEach(System.out::println);
}💥注意:
默认情况下 Mybatis-Plus 会根据 @TableFiled 生成别名,当指定了 QueryWrapper 的 select 属性后就仅仅是属性值而没有了别名。查询出来的结果会对应不上。
更新
完成下述SQL查询:
UPDATE user_info SET delete_flag=? WHERE age < 20测试代码:
@Test
void testUpdateByQueryWrapper(){
QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>()
.lt("age", 20);
UserInfo userInfo = new UserInfo();
userInfo.setDeleteFlag(1);
userInfoMapper.update(userInfo, userInfoQueryWrapper);
}-
lt:"less than" 的缩写,表示小于 -
le:"less than or equal to" 的缩写,表示小于等于 -
ge:"greater than or equal to" 的缩写,表示大于等于 -
gt:"greater than" 的缩写,表示大于 -
eq:"equals" 的缩写,表示等于 -
ne:"not equals" 的缩写,表示不等于
删除
完成下述SQL查询:
DELETE FROM user_info WHERE age = 18测试代码:
@Test
void testDeleteByQueryWrapper(){
QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>()
.eq("age",18);
userInfoMapper.delete(userInfoQueryWrapper);
}2. UpdateWrapper
对于更新,可以直接使用 UpdateWrapper,在不创建实体对象的情况下,直接设置更新字段和条件。
完成下述SQL查询:
UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)测试代码:
@Test
void testUpdateByUpdateWrapper(){
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>()
.set("delete_flag",0)
.set("age", 5)
.in("id", List.of(1,2,3));
userInfoMapper.update(updateWrapper);
}完成下述SQL查询:
UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)测试代码:
@Test
void testUpdateBySQLUpdateWrapper(){
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>()
.setSql("age = age+10")
.in("id", List.of(1,2,3));
userInfoMapper.update(updateWrapper);
}3. LambdaQueryWrapper
QueryWrapper 和 UpdateWrapper 存在一个问题,就是需要写死字段名,如果字段名发生变更,可能会因为测试不到位酿成事故。
MyBatis-Plus 给我们提供了一种基于 Lambda 表达式的条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名 ,也提高了代码的可读性和可维护性。
接下来我们看下具体使用:
@Test
void testLambdaQueryWrapper(){
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>();
queryWrapper.lambda()
.select(UserInfo::getUsername, UserInfo::getPassword,UserInfo::getAge)
.eq(UserInfo::getUserId, 1);
userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
}4. LambdaUpdateWrapper
@Test
void testLambdUpdateByUpdateWrapper(){
UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>();
updateWrapper.lambda()
.set(UserInfo::getDeleteFlag, 0)
.set(UserInfo::getAge, 5)
.in(UserInfo::getUserId, List.of(1,2,3));
userInfoMapper.update(updateWrapper);
}四、自定义SQL
在实际的开发中,MyBatis-Plus 提供的操作可能不能满足我们的实际需求,MyBatis-Plus 也提供了自定义 SQL 的功能,我们可以利用 Wrapper构造查询条件,再结合 Mapper编写 SQL。
💡 📌 为了使用这一功能,mybatis-plus 版本不低于 3.0.7
代码示例1
完成下述SQL查询:
select id,username,password,age FROM user_info WHERE username = "admin"Mapper:
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
@Select("select id,username,password,age FROM user_info ${ew.customSqlSegment}")
List<UserInfo> queryUserByCustom(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);
}测试代码:
@Test
void testQueryUserByCustom(){
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>()
.eq("username","admin");
userInfoMapper.queryUserByCustom(queryWrapper).forEach(System.out::println);
}💥注意事项:
-
参数命名 :在自定义 SQL 传递 Wrapper 对象作为参数时,参数名必须为 **
ew,或者使用注解**@Param(Constants.WRAPPER)** 明确指定参数为 Wrapper 对象** 。 -
在SQL语句中,使用
${ew.customSqlSegment}来引用 Wrapper 对象生成的 SQL 片段。 -
不支持基于 entity 的 where 语句:自定义 SQL 时,Wrapper 对象不会基于实体类自动生成 where 子句,你需要手动编写完整的 SQL 语句。
代码示例2
MyBatis-Plus 在 MyBatis 的基础上只做增强不做改变,所以也支持XML的实现方式。
上述功能也可以使用XML的方式完成:
-
配置mapper路径
mybatis-plus: mapper-locations: "classpath*:/mapper/**.xml" # Mapper.xml -
定义方法
@Mapper public interface UserInfoMapper extends BaseMapper<UserInfo> { List<UserInfo> queryUserByCustom2(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper); } -
编写XML
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.bite.mybatis.plus.mapper.UserInfoMapper"> <select id="queryUserByCustom2"> select id,username,password,age FROM user_info ${ew.customSqlSegment} </select> </mapper> -
测试
@Test void testQueryUserByCustom2(){ QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>() .eq("username","admin"); userInfoMapper.queryUserByCustom2(queryWrapper).forEach(System.out::println); }
代码示例3
完成下述 SQL 查询:
UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)Mapper:
@Update("UPDATE user_info SET age = age+ #{addAge} ${ew.customSqlSegment}")
void updateUserByCustom(@Param("addAge") int addAge, @Param("ew") Wrapper<UserInfo> wrapper);测试代码:
@Test
void updateUserByCustom(){
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>()
.in("id",List.of(1,2,3));
userInfoMapper.updateUserByCustom(10, queryWrapper);
}