前言
MybatisPlus仅仅对Mybatis进行无侵入的增强,这意味着你可以在任何使用了Mybatis的工程下扩展使用MyBatisPlus。
那么为什么要用MybatisPlus 呢?或者说增强了哪部分呢?
首先是支持对单表的快速CRUD,并且支持代码生成、自动分页、逻辑删除、自动填充 、批处理
学习目的
- 简单了解MyBatis实现原理
- 快速对实体类实现单表CRUD功能(自定义Mapper继承BaseMapper<T>)
- 使用QueryWrapper进行查询条件的构造
- 使用UpdateWrapper进行更新操作的构造
- 使用LambdaWrapper优化前两种方式硬编码的问题
- 使用自定义Sql配合Wrapper进一步解决代码灵活性问题
- 复杂业务场景下,继承IService和IServiceImpl实现Service层的增删改查
- 使用Db静态工具类解决循环引用
- 通过配置解决快速实现逻辑删除
- 利用Idea的MybatisPlus插件实现代码生成
MyBatisPlus实现原理
MyBatisPlus通过扫描实体类,基于反射获取实体类信息作为数据库表信息。
主要遵循:
- 类名驼峰转下划线为表名
- id为主键
- 变量驼峰转下划线做字段名
除此之外还可以用注解来指定。这部分的内容以及枚举、分页、参考官方文档
// @TableName 表名
// @TableId 用来指定表中主键字段,,value指定字段名,type指定主键生成类型
// @TableField 普通字段,is开头且是布尔类型以及关键字冲突必须使用
引入依赖
MybatisPlus提供了starter,集成了MyBatis和MybatisPlus的所有功能。所以理论上可以直接进行替换。
注意: 实际生产环境按自己的需求引入,如果有Mybatis改造Plus的需求,一定注意版本问题。
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>
配置
参考官方文档
MyBatisPlus继承了MyBatis配置,同时增加了一些自己的配置
改造的话可能需要增加mapperLocations参数
mybatis-plus:
configuration:
# MyBatis 配置
map-underscore-to-camel-case: true
global-config:
# 全局配置
db-config:
# 数据库配置
id-type: auto
定义Mapper
MybatisPlus提供BaseMapper接口具有以下简单的CRUD,可以直接通过继承接口并指定泛型来使用MybatisPlus提供的功能。
比如我们有一个User类要对其实现简单CRUD(改造同理,可以保留原来的接口但后续使用MybatisPlus提供的方法),可以通过直接继承BaseMapper<User>来实现,然后直接调用就可以了
public interface UserMapper extends BaseMapper<User> {
}
条件构造器Wrapper
辅助构造复杂条件
QueryWrapper
主要生成了where的部分,同时又可以通过select指定选中字段,可以用在大多数增删改查语句
//不难看出下面是一个查询名字里包括三年龄大于等于18的User
//返回Id,name,old,其他功能也类似
QueryWrapper<User> queryWrapper = new QueryWrapper<User>()
.select("id", "name", "old")
.like("name", "三")
.ge("old", 18);
List<User> users = userMapper.selectList(queryWrapper);
UpdateWrapper
主要用于生成update语句,通过setSql指定更新内容,同时支持更新条件,用在需要指定sql的更新语句,比如下面这种。
//自定义一个ids
UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<User>()
.setSql("old= old+ 1");
.in("id",ids);
userMapper.update(null,userUpdateWrapper);
LambdaWrapper
上面两种方法都存在着硬编码的问题,都有写死的部分,LambdaWrapper用于解决这样的问题
利用反射的方式来解决字段问题
LambdaQueryWrapper<User> lambdaWrapper= new LambdaQueryWrapper<User>()
.select(User::getId, User::getName, User::getOld)
.like(User::getName "三")
.ge( User::getOld, 18);
List<User> users = userMapper.selectList(queryWrapper);
结合构造器自定义sql
经过前面的例子不难发现,构造器在构造where的时候十分方便。
而在上面Update的例子,其实还是有一部分代码写死了,对于这种特殊情况,我们可以自定义sql配合构造器生成的where查询条件来完成需求。
1.在UserMapper接口里创建一个方法
//一定要指明@Param(Constants.WRAPPER),或者@Param("ew")才会走自定义sql
//除了在xml里自定义sql还可以在上面有注解写sql
void updateUserById(@Param(Constants.WRAPPER) QueryWrapper<User> userQueryWrapper,@Param("year") int year);
2.在对应xml文件下写sql
${ew.customSqlSegment}负责实现写wrapper的where
他是一个 MyBatis-Plus 提供的属性,用于在包装器(Wrapper)中存储自定义的 SQL 片段。
<update id="updateUserById">
update user set old= old+ #{year} ${ew.customSqlSegment}
</update>
3.构造where语句
int year = 1;
QueryWrapper<User> userQueryWrapper = new QueryWrapper<User>()
.in("id",ids);
//自定义方法
userMapper.updateUserById(userQueryWrapper,year);
IService实现业务逻辑的剥离
IService里面有很多CRUD方法,并由ServiceImpl实现,实践的时候由AbsService继承IService,实现类继承ServiceImpl从而可以使用对MyBatisPlus的提供的功能(下图可以看到部分方法)
因为本质上还是调用BaseMapper所以要指定Mapper以及对应的实体类
public interface IUserService extends IService<User> {
}
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService{
}
Db kit静态工具类
用来解决可能的Service循环注入问题
- 使用 Db Kit 前,需要确保项目中已注入对应实体的 BaseMapper。
- 当参数为 Wrapper 时,需要在 Wrapper 中传入 Entity 或者 EntityClass,以便寻找对应的 Mapper。
- 不建议在循环中频繁调用 Db Kit 的方法,如果是批量操作,建议先将数据构造好,然后使用
Db.saveBatch(数据)
等批量方法进行保存。
public void selectById(Long id) {
List<User> list = Db.lambdaQuery(User.class).eq(User::getId, id).list();
System.out.println(list);
}
逻辑删除
1.配置
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除字段名
logic-delete-value: 1 # 逻辑已删除值
logic-not-delete-value: 0 # 逻辑未删除值
2.在实体类中使用 @TableLogic
注解
import com.baomidou.mybatisplus.annotation.TableLogic;
public class User {
// 其他字段...
@TableLogic
private Integer deleted;
}
idea的MyBatisPlus插件实现代码生成
可以生成实体类和Service、Controller层、以及Mapper
1.下载安装插件
MyBatisPlus
2.配置链接数据库
3.生成代码
TablePrefix是表前缀,表示你在生产代码的时候忽略的内容