MybatisPlus的学习
[MyBatis-Plus] (简称 MP)是一个 [MyBatis] [ (opens new window)] 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
基于Mapper接口CRUD
Insert方法
// 插入一条记录
// T 就是要插入的实体对象
// 默认主键生成策略为雪花算法
int insert(T entity);
类型 | 参数名 | 描述 |
---|---|---|
T | entity | 实体对象 |
Delete方法
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
类型 | 参数名 | 描述 |
---|---|---|
Wrapper<T> | wrapper | 实体对象封装操作类(可以为 null) |
Collection<? extends Serializable> | idList | 主键 ID 列表(不能为 null 以及 empty) |
Serializable | id | 主键 ID |
Map<String, Object> | columnMap | 表字段 map 对象 |
Update方法
// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity,
@Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// 根据 ID 修改 主键属性必须值
int updateById(@Param(Constants.ENTITY) T entity);
类型 | 参数名 | 描述 |
---|---|---|
T | entity | 实体对象 (set 条件值,可为 null) |
Wrapper<T> | updateWrapper | 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) |
Select方法
// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
类型 | 参数名 | 描述 |
---|---|---|
Serializable | id | 主键 ID |
Wrapper<T> | queryWrapper | 实体对象封装操作类(可以为 null) |
Collection<? extends Serializable> | idList | 主键 ID 列表(不能为 null 以及 empty) |
Map<String, Object> | columnMap | 表字段 map 对象 |
IPage<T> | page | 分页查询条件(可以为 RowBounds.DEFAULT) |
常用的方法的代码样例
//查询
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
List<User> userList = userMapper.selectList(null);
System.out.println(userList);
List<Long> list =new ArrayList<>();
list.add(1L);
list.add(3L);
List<User> users=userMapper.selectBatchIds(list);
System.out.println("users = " + users);
}
//添加
@Test
public void testAdd() {
User user = new User();
user.setAge(12);
user.setEmail("xxx");
user.setName("大撒");
int insert = userMapper.insert(user);
System.out.println(insert);
}
//删除
@Test
public void testDelete() {
int i = userMapper.deleteById("1831895769316061185");
System.out.println("i = " + i);
Map map=new HashMap<>();
map.put("age",20);
int i1 = userMapper.deleteByMap(map);
System.out.println("i1 = " + i1);
}
//修改
@Test
public void testUpdate() {
User user=new User();
user.setId(1L);
user.setAge(21);
int i = userMapper.updateById(user);
System.out.println("i = " + i);
User user1=new User();
user.setAge(21);
int i1 = userMapper.update(user,null);
System.out.println("i1 = " + i1);
}
基于Service接口CRUD
对比Mapper接口CRUD区别:
- service添加了批量方法
- service层的方法自动添加事务
使用Iservice接口方式
接口继承IService接口
public interface UserService extends IService<User> {
}
类继承ServiceImpl实现类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{
}
具体方法参考官方文档MyBatis-Plus 🚀 为简化开发而生 (baomidou.com)https://baomidou.com/
MybatisPlus分页查询实现步骤
1.导入分页插件
下面这段代码放到启动类里面
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
2.使用分页查询
@Test
public void testPageQuery(){
//设置分页参数
Page<User> page = new Page<>(1, 5);
userMapper.selectPage(page, null);
//获取分页数据
List<User> list = page.getRecords();
list.forEach(System.out::println);
System.out.println("当前页:"+page.getCurrent());
System.out.println("每页显示的条数:"+page.getSize());
System.out.println("总记录数:"+page.getTotal());
System.out.println("总页数:"+page.getPages());
System.out.println("是否有上一页:"+page.hasPrevious());
System.out.println("是否有下一页:"+page.hasNext());
}
条件构造器使用
使用MyBatis-Plus的条件构造器,你可以构建灵活、高效的查询条件,而不需要手动编写复杂的
SQL 语句。它提供了许多方法来支持各种条件操作符,并且可以通过链式调用来组合多个条件。
这样可以简化查询的编写过程,并提高开发效率。
条件构造器继承结构
Wrapper : 条件构造抽象类,最顶端父类
- AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
- QueryWrapper : 查询/删除条件封装
- UpdateWrapper : 修改条件封装
- AbstractLambdaWrapper : 使用Lambda 语法
- LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
- LambdaUpdateWrapper : Lambda 更新封装Wrapper
不使用QueryWrapper进行修改的原因
1.需要创建对应的实体类
2.无法将列值修改为null值!
使用queryWrapper修改
@Test
public void test04() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//将年龄大于20并且用户名中包含有a或邮箱为null的用户信息修改
//UPDATE t_user SET age=?, email=? WHERE username LIKE ? AND age > ? OR email IS NULL)
queryWrapper
.like("username", "a")
.gt("age", 20)
.or()
.isNull("email");
User user = new User();
user.setAge(18);
user.setEmail("user@atguigu.com");
int result = userMapper.update(user, queryWrapper);
System.out.println("受影响的行数:" + result);
}
使用updateWrapper修改
@Test
public void testQuick2(){
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
//将id = 3 的email设置为null, age = 18
updateWrapper.eq("id",3)
.set("email",null) // set 指定列和结果
.set("age",18);
//如果使用updateWrapper 实体对象写null即可!
int result = userMapper.update(null, updateWrapper);
System.out.println("result = " + result);
}
LambdaQueryWrapper对比QueryWrapper优势
QueryWrapper 示例代码:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "John")
.ge("age", 18)
.orderByDesc("create_time")
.last("limit 10");
List<User> userList = userMapper.selectList(queryWrapper);
LambdaQueryWrapper 示例代码:
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(User::getName, "John")
.ge(User::getAge, 18)
.orderByDesc(User::getCreateTime)
.last("limit 10");
List<User> userList = userMapper.selectList(lambdaQueryWrapper);
从上面的代码对比可以看出,相比于 QueryWrapper,LambdaQueryWrapper 使用了实体类的属
性引用(例如 User::getName、User::getAge),而不是字符串来表示字段名,这提高了代码的可
读性和可维护性。
核心注解使用
@TableName注解
- 描述:表名注解,标识实体类对应的表
- 使用位置:实体类
@TableName("sys_user") //对应数据库表名
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
特殊情况:如果表名和实体类名相同(忽略大小写)可以省略该注解!
其他解决方案:全局设置前缀
mybatis-plus: # mybatis-plus的配置
global-config:
db-config:
table-prefix: sys_ # 表名前缀字符串
@TableId 注解
- 描述:主键注解
- 使用位置:实体类主键字段
@TableName("sys_user")
public class User {
@TableId(value="主键列名",type=主键策略)
private Long id;
private String name;
private Integer age;
private String email;
}
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | "" | 主键字段名 |
type | Enum | 否 | IdType.NONE | 指定主键类型 |
IdType属性可选值:
值 | 描述 |
---|---|
AUTO | 数据库 ID 自增 (mysql配置主键自增长) |
ASSIGN_ID(默认) | 分配 ID(主键类型为 Number(Long )或 String)(since 3.3.0),使用接口IdentifierGenerator 的方法nextId (默认实现类为DefaultIdentifierGenerator 雪花算法) |
全局配置修改主键策略:
mybatis-plus:
configuration:
# 配置MyBatis日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
# 配置MyBatis-Plus操作表的默认前缀
table-prefix: t_
# 配置MyBatis-Plus的主键策略
id-type: auto
在以下场景下,添加`@TableId`注解是必要的:
1. 实体类的字段与数据库表的主键字段不同名:如果实体类中的字段与数据库表的主键字段不一
致,需要使用`@TableId`注解来指定实体类中表示主键的字段。
2. 主键生成策略不是默认策略:如果需要使用除了默认主键生成策略以外的策略,也需要添加
@TableId`注解,并通过`value`属性指定生成策略。
@TableField注解
描述:字段注解(非主键)
@TableName("sys_user")
public class User {
@TableId
private Long id;
@TableField("nickname")
private String name;
private Integer age;
private String email;
}
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | " " | 数据库字段名 |
exist | boolean | 否 | true | 是否为数据库表字段 |
逻辑删除实现
概念:
逻辑删除,可以方便地实现对数据库记录的逻辑删除而不是物理删除。逻辑删除是指通过更改记录的状态或添加标记字段来模拟删除操作,从而保留了删除前的数据,便于后续的数据分析和恢复。
- 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
- 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据 库中仍旧能看到此条数据记录
逻辑删除实现步骤:
1.数据库和实体类添加逻辑删除字段
2.指定逻辑删除字段和属性值
a.单一指定
@Data
public class User {
// @TableId
private Integer id;
private String name;
private Integer age;
private String email;
@TableLogic
//逻辑删除字段 int mybatis-plus下,默认 逻辑删除值为1 未逻辑删除 1
private Integer deleted;
}
b.全局指定
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
逻辑删除以后,没有真正的删除语句,删除改为修改语句!
使用mybatis-plus数据使用乐观锁
1. 添加版本号更新插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
2.乐观锁字段添加@Version注解
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 仅支持 `updateById(id)` 与 `update(entity, wrapper)` 方法
@Version
private Integer version;
3.正常更新使用即可
//演示乐观锁生效场景
@Test
public void testQuick7(){
//步骤1: 先查询,在更新 获取version数据
//同时查询两条,但是version唯一,最后更新的失败
User user = userMapper.selectById(5);
User user1 = userMapper.selectById(5);
user.setAge(20);
user1.setAge(30);
userMapper.updateById(user);
//乐观锁生效,失败!
userMapper.updateById(user1);
}