MyBatisPlus常用功能总结!(附项目示例)
这篇主要是总结一下MybatisPlus一些常用的场景,目前主要有以下几点:
- 完整的CURD操作示例
- 逻辑删除功能示例
- 自动填充功能示例
- 分页插件功能示例
有关一些其它重要的功能比如 条件生成器、主键策略、通用枚举、多数据源、乐观锁、多租户等功能可以看官方文档,官方文档已经写的很清楚了,而且每个功能点都有对应的项目示例。
示例准备
1、用户表
CREATE TABLE `user` (
`id` int unsigned AUTO_INCREMENT COMMENT '主键',
`username` varchar(128) COMMENT '用户名',
`phone` varchar(32) COMMENT '手机号',
`sex` char(1) COMMENT '性别',
`create_time` datetime COMMENT '创建时间',
`update_time` datetime COMMENT '更新时间',
`deleted` tinyint DEFAULT '0' COMMENT '1、删除 0、未删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1
2、创建对应实体
@Data
@Accessors(chain = true)
@TableName("user")
public class UserDO implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 用户名
*/
@TableField("username")
private String username;
/**
* 手机号
*/
@TableField("phone")
private String phone;
/**
* 性别
*/
@TableField("sex")
private String sex;
/**
* 创建时间
*/
@TableField("create_time")
private LocalDateTime createTime;
/**
* 更新时间
*/
@TableField("update_time")
private LocalDateTime updateTime;
/**
* 1、删除 0、未删除
*/
@TableField("deleted")
private Integer deleted;
}
3、创建Mapper
@Mapper
public interface UserMapper extends BaseMapper<UserDO> {
}
其它有关代码这里就不粘贴了,具体看项目源码就可以了。
一、完整的CURD操作
public class UserServiceTest extends Base {
@Autowired
private UserMapper mapper;
@Test
public void insert() {
UserDO user = new UserDO();
user.setUsername("小小");
user.setPhone("18812345678");
user.setSex("女");
Assertions.assertThat(mapper.insert(user)).isGreaterThan(0);
// 成功直接拿回写的 ID
Assertions.assertThat(user.getId()).isNotNull();
}
@Test
public void delete() {
mapper.deleteById(6);
mapper.delete(new LambdaQueryWrapper<UserDO>().eq(UserDO::getUsername, "张三"));
}
@Test
public void update() {
//方式一: 根据id更新
mapper.updateById(new UserDO().setId(1).setPhone("13312345678"));
//方式二: 左边是需要更新的值 右边是where条件
mapper.update(
new UserDO().setDeleted(1), new LambdaQueryWrapper<UserDO>().eq(UserDO::getPhone, "18812345678")
);
//方式三:不创建User对象
mapper.update(null,new LambdaUpdateWrapper<UserDO>()
.set(UserDO::getPhone,"13111111111").set(UserDO::getCreateTime, LocalDateTime.now()).eq(UserDO::getUsername,"小小"));
}
@Test
public void select() {
//1、根据主键获取
UserDO userDO = mapper.selectById(1);
//2、根据手机号获取 单个
UserDO userDO1 = mapper.selectOne(new LambdaQueryWrapper<UserDO>().eq(UserDO::getPhone, "13312345678"));
//3、获取集合
List<UserDO> userDOS = mapper.selectList(new LambdaQueryWrapper<UserDO>().eq(UserDO::getPhone, "13312345678"));
List<UserDO> userDOS1 = mapper.selectList(null);
}
@Test
public void orderBy() {
//1、单个排序
List<UserDO> users = mapper.selectList(Wrappers.<UserDO>query().orderByAsc("create_time"));
//2、多字段排序
List<UserDO> users2 = mapper.selectList(Wrappers.<UserDO>query().orderByAsc(Lists.newArrayList("create_time","phone")));
//3、先按手机号升序排列,phone相同再按create_time降序排列
List<UserDO> users3 = mapper.selectList(Wrappers.<UserDO>query().orderByAsc("phone").orderByDesc("create_time"));
//4、Lambda实现方式,和3实现的效果是一样的。
List<UserDO> users4 = mapper.selectList(new LambdaQueryWrapper<UserDO>().orderByAsc(UserDO::getPhone).orderByDesc(UserDO::getCreateTime));
}
@Test
public void groupBy() {
QueryWrapper<UserDO> wrapper = new QueryWrapper<>();
wrapper.select("phone, count(*) as total")
.groupBy("phone");
//注意要用 listMaps ,返回的是 Map<String,Object>
List<Map<String, Object>> maplist = mapper.selectMaps(wrapper);
}
@Test
public void testSelectMaxId() {
QueryWrapper<UserDO> wrapper = new QueryWrapper<>();
wrapper.select("max(id) as id");
UserDO user = mapper.selectOne(wrapper);
}
}
二、逻辑删除功能
1、使用场景
这个场景是这样的,因为我们在设计表结构的时候都会有一个逻辑删除字段,比如上表中就有一个deleted字段,1=删除 0=未删除。
那我们在查询或者更新操作时,sql都会带上这个字段。
例如:
-- 更新
update user set sex='女' where id = 1 and deleted=0
-- 查询
select id,sex,username from user where deleted=0
既然都要带上,那是不是可以做成全局的,不用我们每个sql都手动添加deleted=0,这个条件。
2、使用方法
1、配置
例如: application.yml
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除的实体字段名()
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
2、实体类字段上加上@TableLogic注解
@TableLogic
private Integer deleted;
注意
:since 3.3.0,配置后可以忽略不配置这步骤
3、示例
public class UserServiceDeleteTest extends Base {
@Autowired
private UserMapper mapper;
@Test
public void update() {
//方式一: 根据id更新
mapper.updateById(new UserDO().setId(1).setPhone("13312345678"));
//实际执行sql: UPDATE user SET phone=? WHERE id=? AND deleted=0
}
@Test
public void select() {
//1、根据主键获取
UserDO userDO = mapper.selectById(1);
//实际执行sql: SELECT id,username,phone,sex,create_time,update_time,deleted FROM user WHERE id=? AND deleted=0
}
}
上面两条sql虽然没有加入deleted=0这个条件,但因为加了全局配置,所以会自动加上deleted=0条件。
三、自动填充功能
1、使用背景
我们在设计表的时候,会有创建人ID,创建人名称,创建时间,更新人ID,更新人名称,更新时间。
我们在新增或者更新数据的时候,都会修改这些数据。所以我们也可以做成全局的。
2、使用方式
1、实体添加注解
/**
* 创建时间
*/
@TableField(value = "create_time",fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 更新时间
*/
@TableField(value = "update_time",fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
FieldFill一共有4种属性,默认是DEFAULT
public enum FieldFill {
DEFAULT,
INSERT,
UPDATE,
INSERT_UPDATE;
}
2、自定义实现类 MyMetaObjectHandler
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
//设置属性值
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
3、测试
@Test
public void insert() {
UserDO user = new UserDO();
user.setUsername("小小");
user.setPhone("18812345678");
user.setSex("女");
Assertions.assertThat(mapper.insert(user)).isGreaterThan(0);
// 成功直接拿回写的 ID
Assertions.assertThat(user.getId()).isNotNull();
}
用上面这个测试用例,发现虽然这里没有插入创建时间和更新时间,但打印sql发现插入该属性。
==> Preparing: INSERT INTO user ( username, phone, sex, create_time, update_time ) VALUES ( ?, ?, ?, ?, ? )
==> Parameters: 小小(String), 18812345678(String), 女(String), 2022-09-27T16:40:00.682(LocalDateTime), 2022-09-27T16:40:00.687(LocalDateTime)
<== Updates: 1
4、注意事项
- 填充原理是直接给
entity
的属性设置值!!! - 注解则是指定该属性在对应情况下必有值,如果无值则入库会是
null
MetaObjectHandler
提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为null
则不填充- 字段必须声明
TableField
注解,属性fill
选择对应策略,该声明告知Mybatis-Plus
需要预留注入SQL
字段 - 填充处理器
MyMetaObjectHandler
在 Spring Boot 中需要声明@Component
或@Bean
注入 - update(T t,Wrapper updateWrapper)时t不能为空,否则自动填充失效
四、分页功能示例
1、配置类
@Configuration
public class MybatisPlusPageConfig {
/**
* 新的分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
2、示例
public class UserServicePageTest extends Base {
@Autowired
private UserMapper mapper;
@Test
public void page() {
Page<UserDO> page = new Page<>(1, 3);
Page<UserDO> result = mapper.selectPage(page, new LambdaQueryWrapper<UserDO>().eq(UserDO::getDeleted, 0));
}
}
这里有点需要注意: MybatisPlus 与 pagehelper 存在依赖 jsqlparser 冲突,不建议混用
项目地址
: https://github.com/yudiandemingzi/spring-boot-study