MyBatis-Plus使⽤
1. MyBatis-Plus介绍
MyBatis-Plus(简称MP)是MyBatis的增强工具,在保留MyBatis原有功能的基础上,简化了开发流程,提供了通用的CRUD操作、条件构造器、分页插件等高效功能。其核心目标是提高开发效率,减少重复代码。
2. 快速上⼿
数据准备
-- 创建表[用户表]
DROP TABLE IF EXISTS user_info;
CREATE TABLE `user_info` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL,`password` VARCHAR ( 127 ) NOT NULL,`age` TINYINT ( 4 ) NOT NULL,`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-女 0-默认',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; -- 添加用户信息
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
项⽬准备
添加依赖:
Spring Boot2(Java 8+)
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.7</version></dependency>
Spring Boot3(Java 17+)
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.5</version></dependency>
配置数据库
# 数据库连接配置
spring:application:name: mybatis-plus-demodatasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: lqmyyds123driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:configuration: # 配置打印MyBatis⽇志log-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations: "classpath*:/mapper/**.xml" # Mapper.xml
编码
创建实体类UserInfo
@Data
//通过指定名称确定数据库的表名
@TableName("user_info")
public class UserInfo {//@TableId("id")//指定这是具体主键的ID@TableId(value= "id" , type = IdType.AUTO)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;
}
编写Mapper接⼝类
@Mapper
public interface UserMapper extends BaseMapper<UserInfo> {
}
CRUD单元测试
具体测试结果自行运行观察
@SpringBootTest
class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testvoid testInsert() {UserInfo user = new UserInfo();user.setUsername("whhhhh");user.setPassword("123456");user.setAge(11);user.setGender(0);user.setPhone("18610001234");userMapper.insert(user);}@Testvoid testSelectById() {UserInfo user = userMapper.selectById(1L);System.out.println("user: " + user);}@Testvoid testSelectByIds() {List<UserInfo> userInfos = userMapper.selectBatchIds(List.of(1L, 2L, 3L, 4L));userInfos.forEach(System.out::println);}@Testvoid updateById() {UserInfo userInfo = new UserInfo();userInfo.setId(1);userInfo.setPassword("4444444");userMapper.updateById(userInfo);}@Testvoid testDelete() {userMapper.deleteById(78721026L);}
3. MyBatis-Plus复杂操作
在上⾯的程序中,MyBatis是如何知道,我们要操作的是哪张表,表⾥有哪些字段呢?
UserInfoMapper 在继承BaseMapper 时,指定了⼀个泛型,这个UserInfo就是与数据库表相对应的实体类. MyBatis-Plus会根据这个实体类来推断表的信息
默认情况下:
- 表名:实体类的驼峰表⽰法转换成蛇形表⽰法(下划线分割),作为表名.⽐如UserInfo->user_info
- 字段:根据实体类的属性名转换为蛇形表⽰法作为字段名.⽐如deleteFlag->delete_flag
- 主键:默认为id
常⻅注解
@TableName
通过 @TableName 来标识实体类对应的表
@TableName("user_info")
@TableField
修改属性名deleteFlag为deleteflag,重新执⾏测试⽅法testSelectById
@TableField("delete_flag")
@TableId
修改属性名id为userId,重新执⾏测试⽅法testSelectById
@TableId("id")
条件构造
- MyBatis-Plus 的条件构造器(Wrapper)提供了一种面向对象的方式构建复杂查询条件,避免直接编写 SQL,同时支持链式调用以提升代码可读性。
- AbstractWrapper:这是⼀个抽象基类,提供了所有Wrapper类共有的⽅法和属性.详细参考官⽹ 介绍:条件构造器
- QueryWrapper:⽤于构造查询条件,在AbstractWrapper的基础上拓展了⼀个select⽅法,允许指 定查询字段.
- UpdateWrapper:⽤于构造更新条件,可以在更新数据时指定条件.
- LambdaQueryWrapper:基于Lambda表达式的查询条件构造器,它通过Lambda表达式来引⽤ 实体类的属性,从⽽避免了硬编码字段名.
- LambdaUpdateWrapper:基于Lambda表达式的更新条件构造器,它允许你使⽤Lambda表达 式来指定更新字段和条件,同样避免了硬编码字段名的问题.
QueryWrapper
QueryWrapper并不只⽤于查询语句,⽆论是修改,删除,查询,都可以使⽤QueryWrapper来构建查询条 件
方法注解:
- lt :"less than" 的缩写,表⽰⼩于.
- le :"lessthanorequalto"的缩写,表⽰⼩于等于
- ge :"greaterthanorequalto"的缩写,表⽰⼤于等于.
- gt :"greaterthan"的缩写,表⽰⼤于.
- eq :"equals"的缩写,表⽰等于.
- ne :"notequals"的缩写,表⽰不等于.
查询
SELECT id,username,password,age FROM user_info WHERE age = 18 AND username
"%min%"
测试代码
// SELECT id,username,password,age FROM user_info WHERE age = 18 AND username//"%min%"@Testvoid testQueryWrapper(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();queryWrapper.select("id","username","password","age").eq("age",18).like("username", "min");List<UserInfo> list = userMapper.selectList(queryWrapper);list.stream().forEach(x -> System.out.println(x));// list.forEach(System.out::println);//等价}
更新
UPDATE user_info SET delete_flag=? WHERE age < 20
测试代码
@Testvoid testUpdateWrapper(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();queryWrapper.eq("id",3);//queryWrapper.lt("age",20);UserInfo userInfo = new UserInfo();userInfo.setAge(18);userMapper.update(userInfo,queryWrapper);}
删除
@Testvoid testDeleteWrapper(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();queryWrapper.eq("age",18);userMapper.delete(queryWrapper);}
UpdateWrapper
对于更新,我们也可以直接使⽤UpdateWrapper,在不创建实体对象的情况下,直接设置更新字段和条 件
基础更新:
UPDATE user_info SET delete_flag=0, age=5 WHERE id IN (1,2,3)
测试代码
@Testvoid upByTestUpdateWrapper(){UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.set("delete_flag",0).set("age",18).in("id",List.of(5,6,7));userMapper.update(updateWrapper);}
基于SQL更新:
UPDATE user_info SET age = age+10 WHERE id IN (1,2,3)
测试代码
@Testvoid upByTestUpdateWrapper1(){UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.setSql("age = age+10").in("id",List.of(1,3));userMapper.update(updateWrapper);}
LambdaQueryWrapper
QueryWrapper和UpdateWrapper存在⼀个问题,就是需要写死字段名,如果字段名发⽣变更,可能会 因为测试不到位酿成事故.
MyBatis-Plus 给我们提供了⼀种基于Lambda表达式的条件构造器,它通过Lambda表达式来引⽤实体 类的属性,从⽽避免了硬编码字段名,也提⾼了代码的可读性和可维护性.
@Testvoid testLambdaQueryWrapper(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().select(UserInfo::getUsername,UserInfo::getPassword).eq(UserInfo::getId,1);UserInfo userInfo = userMapper.selectOne(queryWrapper);System.out.println(userInfo);}
LambdaUpdateWrapper
@Testvoid testLambdUpdateByUpdateWrapper(){UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>();updateWrapper.lambda().set(UserInfo::getDeleteflag, 0).set(UserInfo::getAge, 5).in(UserInfo::getId, List.of(1,2,3));userMapper.update(updateWrapper);}
⾃定义SQL
MyBatis-Plus提供的操作不能满⾜我们的实际需求,MyBatis-Plus也提供了⾃定义 SQL的功能,我们可以利⽤Wrapper构造查询条件,再结合Mapper编写SQL
完成下述SQL查询
select id,username,password,age FROM user_info WHERE username = "admin"
Mapper:
@Mapperpublic 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);}
测试代码
@Testvoid testQueryUserByCustom(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>().eq("username","admin");userInfoMapper.queryUserByCustom(queryWrapper).forEach(System.out::println);}
注意事项:
- 参数命名:在⾃定义SQL时,传递Wrapper对象作为参数时,参数名必须为 ew ,或者使⽤注解 @Param(Constants.WRAPPER) 明确指定参数为Wrapper对象.
- 使⽤ ${ew.customSqlSegment} :在SQL语句中,使⽤ 引⽤Wrapper对象⽣成的SQL⽚段. ${ew.customSqlSegment} 来
- 不⽀持基于entity的where语句:⾃定义SQL时,Wrapper对象不会基于实体类⾃动⽣成 where⼦句,你需要⼿动编写完整的SQL语句.
也可以使用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>