本文最后更新于48 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
一、快速入门
1、入门案例
- 引入MybatisPlus的起步依赖
MyBatisPlus官方提供了starter,其中集成了Mybatis和MybatisPlus的所有功能,并且实现了自动装配效果。因此我们可以用MybatisPlus的starter代替Mybatis的starter:
<!--MybatisPlus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
- 定义Mapper
自定义的Mapper继承MybatisPlus提供的BaseMapper接口:
public interface UserMapper extends BaseMapper<User> {
}
2、常见注解
- MyBatisPlus通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。
- 常用的几个注解:
@TableName:用来指定表名
@TableId:用来指定表中的主键字段信息
@TableField:用来指定表中的普通字段信息
IdType枚举:
AUTO:数据库自增长
INPUT:通过set方法自行输入
ASSIGN_ID:分配 ID,接口IdentifierGenerator的方法nextId来生成id,默认实现类为DefaultIdentifierGenerator雪花算法
使用@TableField的常见场景:
变量名与数据库字段名不一致
变量名以is开头,且是布尔值
变量名与数据库关键字冲突
变量不是数据库字段,如@TableField(exist = false)
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、条件构造器
MyBatisPlus支持各种复杂的where条件,可以满足日常开发的所有需求。
- 查询出名字中带o的,存款大于等于1000元的人的id、username、info、balance字段
SELECT id,username,info,balance
FROM user
WHERE username LIKE ? AND balance >= ?
void testQuerywrapper(){
//1.构建查询条件
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.select("id",,"username","info","balance")
.llike( column: "username", val: "o")
·ge( column: "balance",val: 1000);
// 2.查询
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
// 参数是函数,避免硬编码,比如User::getId就是User的getId方法
void testQuerywrapper(){
//1.构建查询条件
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
.select(User::getId,User::getUsername,User::getInfo,User::getBalance)
.like(User::getUsername, val:"o")
·ge(User::getBalance, val:1000);
// 2.查询
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
- 更新用户名为jack的用户的余额为2000
UPDATE user
SET balance = 2000
WHERE (username = "jack")
void testUpdateByQueryWrapper(){
// 1.要更新的数据
User user = new User();
user.setBalance(2000) ;
//2.更新的条件
QueryWrapper<User> wrapper = new QueryWrapper<User>().eq( column: "username",val: "jack");
//3.执行更新I
userMapper.update(user, wrapper) ;
}
- 更新id为1,2,4的用户的余额,扣200
UPDATE user
SET balance = balance - 200
WHERE id in (1, 2, 4)
void testUpdateWrapper(){
List<Long> ids = List.of(1L,2L,4L);
UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
.SetSql("balance = balance - 2oo")
.in( column: "id", ids);I
userMapper.update( entity: null, wrapper);
}
2、自定义SQL
利用MyBatisPlus的Wrapper来构建复杂的Where条件,然后自己定义SQL语句中剩下的部分。
- 基于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);
- 在mapper方法参数中用Param注解声明wrapper变量名称,必须是ew
void updateBalanceByIds(@Param("ew") LambdaQueryWrapper<User> wrapper, @Param("amount") int amount);
- 自定义SQL,并使用Wrapper条件
<update id="updateBalanceByIds">
UPDATE tb_user SET balance = balance - #{amount} ${ew.customSqlSegment}
</update>
3、Service接口
// 自定义Service接口继承IService接口
public interface IUserService extends IService<User> {}
// 自定义Service实现类,实现自定义接口并继承ServiceImpl类
// ServiceImpl<UserMapper, User>:用到的mapper和实体
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}
三、扩展功能
1、代码生成
idea中存在插件MybatisPlus,能够代码生成。
2、静态工具
3、逻辑删除
基于代码逻辑模拟删除效果,但并不会真正删除数据。
- 思路如下:
- 在表中添加一个字段标记数据是否被删除
- 当删除数据时把标记置为1
- 查询时只查询标记为0的数据
- 删除操作:
// 例如逻辑删除字段为deleted
UPDATE user SET deleted = 1 WHERE id = 1 AND deleted = 0
- 查询操作:
SELECT * FROM user WHERE deleted = 0
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名,字段类型可以是boolean、integer
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
4、枚举处理器
假如一个实体中有大量的枚举类型,为了避免冗余,需要全局的处理器。
@Getter
enum UserStatus {
NORMAL(1, "正常"),
FROZEN(2, "冻结");
@EnumValue // 标记这个字段的值存入数据库
private final int value;
@JsonValue
private final String desc;
// 构造方法名必须与枚举类名一致
UserStatus(int value, String desc) {
this.value = value;
this.desc = desc;
}
}
mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
5、JSON处理器
四、插件功能
MyBatisPlus基于MyBatis的Interceptor实现了一个基础拦截器,并在内部保存了MyBatisPlus的内置拦截器的集合:
序号 | 拦截器拦截器 | 描述描述 |
1 | TenantLineInnerInterceptor | 多租户插件 |
2 | DynamicTableNameInnerInterceptor | 动态表名插件 |
3 | PaginationInnerInterceptor | 分页插件 |
4 | OptimisticLockerInnerInterceptor | 乐观锁插件 |
5 | IllegalSQLInnerInterceptor | SQL性能规范插件,检测并拦截垃圾SQL |
6 | BlockAttackInnerInterceptor | 防止全表更新和删除的插件 |
1、分页插件
在配置类中注册MyBatisPlus的核心插件,同时添加分页插件:
@Configuration
public class MybatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
//1.初始化核心插件
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//2.添加分页插件
PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
pageInterceptor.setMaxLimit(1000L);
//3.设置分页上限
interceptor.addInnerInterceptor(pageInterceptor);
return interceptor;
}
}
@Test
void testPageQuery() {
// 1.查询
int pageNo = 1, pageSize = 5;
// 1.1.分页参数
Page<User> page = Page.of(pageNo, pageSize);
// 1.2.排序参数, 通过OrderItem来指定
page.addOrder(new OrderItem("balance", false));
// 1.3.分页查询
Page<User> p = userService.page(page);
// 2.总条数
System.out.println("total = " + p.getTotal());
// 3.总页数
System.out.println("pages = " + p.getPages());
// 4.分页数据
List<User> records = p.getRecords();
records.forEach(System.out::println);
}