MP的CRUD详解
1-准备
数据库表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`
(
id BIGINT NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO `user` (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
SpringBoot基础项目
2-新增
mapper
方法 insert(T entity);
参数解释
类型 | 参数名 | 描述 |
---|---|---|
T | entity | 实体对象 |
// 插入一条记录
int insert(T entity);
Users users = Users.builder()
.age(18)
.email("330001112@333")
.name("殷桃")
.build();
int insert = usersMapper.insert(users);
System.out.println("增添了"+insert+"数据");
SQL:INSERT INTO users ( name, age, email ) VALUES ( '殷桃', 18, '330001112@333' )
增添了1数据
service
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);
类型 | 参数名 | 描述 |
---|---|---|
T | entity | 实体对象 |
Collection | entityList | 实体对象集合 |
int | batchSize | 插入批次数量 |
批量新增
Users users = Users.builder()
.age(18)
.email("330001112@333")
.name("殷桃2")
.build();
Users users1 = Users.builder()
.age(18)
.email("330001112@333")
.name("殷桃1")
.build();
boolean b = usersService.saveBatch(Arrays.asList(users, users1));
System.out.println("批量新增"+b);
INSERT INTO users ( name, age, email ) VALUES ( '殷桃2', 18, '330001112@333' )
Consume Time:0 ms 2023-12-10 20:56:22
Execute SQL:INSERT INTO users ( name, age, email ) VALUES ( '殷桃1', 18, '330001112@333' )
批量新增true
由此可见 批量新增为伪批量新增
通过循环单条数据进行新增
// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
数据库存在就更新,不存在就新增
类型 | 参数名 | 描述 |
---|---|---|
T | entity | 实体对象 |
Wrapper | updateWrapper | 实体对象封装操作类 UpdateWrapper |
Collection | entityList | 实体对象集合 |
int | batchSize | 插入批次数量 |
Users users = Users.builder()
.age(18)
.email("330001112@333")
.name("殷桃3")
.build();
Users users1 = Users.builder()
.id(8)
.age(18)
.email("666666@333")
.name("殷桃1")
.build();
boolean b= usersService.saveOrUpdateBatch(Arrays.asList(users,users1));
System.out.println("批量新增和修改"+b);
Consume Time:1 ms 2023-12-10 21:04:32
Execute SQL:INSERT INTO users ( name, age, email ) VALUES ( '殷桃3', 18, '330001112@333' )
Consume Time:0 ms 2023-12-10 21:04:32
Execute SQL:SELECT id,name,age,email FROM users WHERE id=8
Consume Time:0 ms 2023-12-10 21:04:32
Execute SQL:UPDATE users SET name='殷桃1', age=18, email='666666@333' WHERE id=8
批量新增和修改true
3-删除
mapper
// 根据 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 | wrapper | 实体对象封装操作类(可以为 null) |
Collection<? extends Serializable> | idList | 主键 ID 列表(不能为 null 以及 empty) |
Serializable | id | 主键 ID |
Map<String, Object> | columnMap | 表字段 map 对象 |
批量删除
int i = usersMapper.deleteBatchIds(Arrays.asList(1, 2));
System.out.println("删除"+i+"条数据");
Execute SQL:DELETE FROM users WHERE id IN ( 1 , 2 )
删除2条数据
map删除
HashMap<String, Object> map = new HashMap<>();
map.put("name","殷桃1");
int i = usersMapper.deleteByMap(map);
System.out.println("删除"+i+"条数据");
Execute SQL:DELETE FROM users WHERE name = '殷桃1'
删除1条数据
service
// 根据 queryWrapper 设置的条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);
参数说明
类型 | 参数名 | 描述 |
---|---|---|
Wrapper | queryWrapper | 实体包装类 QueryWrapper |
Serializable | id | 主键 ID |
Map<String, Object> | columnMap | 表字段 map 对象 |
Collection<? extends Serializable> | idList | 主键 ID 列表 |
条件删除
LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
lqw.eq(Users::getName,"殷桃3");
boolean remove = usersService.remove(lqw);
System.out.println("删除"+remove);
Execute SQL:DELETE FROM users WHERE (name = '殷桃3')
删除true
**请注意,**LambdaQueryWrapper是条件构造器,参考
条件构造器 | MyBatis-Plus (baomidou.com)
4-修改
mapper
// 根据 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 | updateWrapper | 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) |
根据id修改
usersMapper.updateById(Users.builder()
.id(3)
.name("Mike")
.build());
Consume Time:28 ms 2023-12-10 21:29:23
Execute SQL:UPDATE users SET name='Mike' WHERE id=3
service
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);
参数说明
类型 | 参数名 | 描述 |
---|---|---|
Wrapper | updateWrapper | 实体对象封装操作类 UpdateWrapper |
T | entity | 实体对象 |
Collection | entityList | 实体对象集合 |
int | batchSize | 更新批次数量 |
根据 UpdateWrapper 条件更新
UpdateWrapper<Users> upw = new UpdateWrapper<>();
upw.lambda().set(Users::getName,"Jack").eq(Users::getId,7);
usersService.update(upw);
Execute SQL:UPDATE users SET name='Jack' WHERE (id = 7)
5-查询
mapper
// 根据 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 | queryWrapper | 实体对象封装操作类(可以为 null) |
Collection<? extends Serializable> | idList | 主键 ID 列表(不能为 null 以及 empty) |
Map<String, Object> | columnMap | 表字段 map 对象 |
IPage | page | 分页查询条件(可以为 RowBounds.DEFAULT) |
selectCount
Long aLong = usersMapper.selectCount(null);
System.out.println("共查询"+aLong+"条数据");
Execute SQL:SELECT COUNT( * ) FROM users
selectList
List<Users> users = usersMapper.selectList(null);
users.forEach(users1 -> System.out.println(users1));
Execute SQL:SELECT id,name,age,email FROM users
Users(id=3, name=Mike, age=28, email=test3@baomidou.com)
Users(id=4, name=Sandy, age=21, email=test4@baomidou.com)
Users(id=5, name=Billie, age=24, email=test5@baomidou.com)
Users(id=6, name=殷桃, age=18, email=330001112@333)
Users(id=7, name=Jack, age=18, email=330001112@333)
selectByMap
Map<String, Object> map = new HashMap<>();
map.put("age",18);
List<Users> users = usersMapper.selectByMap(map);
users.forEach(users1 -> System.out.println(users1));
Execute SQL:SELECT id,name,age,email FROM users WHERE age = 18
Users(id=6, name=殷桃, age=18, email=330001112@333)
Users(id=7, name=Jack, age=18, email=330001112@333)
selectPage和selectMapsPage
需要使用分页插件,后续再讲解
service
Get
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
参数说明
类型 | 参数名 | 描述 |
---|---|---|
Serializable | id | 主键 ID |
Wrapper | queryWrapper | 实体对象封装操作类 QueryWrapper |
boolean | throwEx | 有多个 result 是否抛出异常 |
T | entity | 实体对象 |
Function<? super Object, V> | mapper | 转换函数 |
getOne
LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
lqw.eq(Users::getName,"Mike");
Users one = usersService.getOne(lqw);
System.out.println(one);
Execute SQL:SELECT id,name,age,email FROM users WHERE (name = 'Mike')
Users(id=3, name=Mike, age=18, email=test3@baomidou.com)
List
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
参数说明
类型 | 参数名 | 描述 |
---|---|---|
Wrapper | queryWrapper | 实体对象封装操作类 QueryWrapper |
Collection<? extends Serializable> | idList | 主键 ID 列表 |
Map<String, Object> | columnMap | 表字段 map 对象 |
Function<? super Object, V> | mapper | 转换函数 |
listMaps
LambdaQueryWrapper<Users> lqw = new LambdaQueryWrapper<>();
lqw.eq(Users::getName,"Mike");
List<Map<String, Object>> list = usersService.listMaps(lqw);
list.forEach(map -> System.out.println(map));
Execute SQL:SELECT id,name,age,email FROM users WHERE (name = 'Mike')
{name=Mike, id=3, age=18, email=test3@baomidou.com}
Page
// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
参数说明
类型 | 参数名 | 描述 |
---|---|---|
IPage | page | 翻页对象 |
Wrapper | queryWrapper | 实体对象封装操作类 QueryWrapper |
同mapper需要使用分页插件
Count
// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);
count
long count = usersService.count();
System.out.println("共"+count+"条数据");
Execute SQL:SELECT COUNT( * ) FROM users
共5条数据
参数说明
类型 | 参数名 | 描述 |
---|---|---|
Wrapper | queryWrapper | 实体对象封装操作类 QueryWrapper |
6-分页查询
使用分页插件
创建MybatisPlusConfig配置类
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
}
Page
该类继承了
IPage
类,实现了简单分页模型
如果你要实现自己的分页模型可以继承Page
类或者实现IPage
类
属性名 | 类型 | 默认值 | 描述 |
---|---|---|---|
records | List | emptyList | 查询数据列表 |
total | Long | 0 | 查询列表总记录数 |
size | Long | 10 | 每页显示条数,默认 10 |
current | Long | 1 | 当前页 |
orders | List | emptyList | 排序字段信息,允许前端传入的时候,注意 SQL 注入问题,可以使用 SqlInjectionUtils.check(...) 检查文本 |
optimizeCountSql | boolean | true | 自动优化 COUNT SQL 如果遇到 jSqlParser 无法解析情况,设置该参数为 false |
optimizeJoinOfCountSql | boolean | true | 自动优化 COUNT SQL 是否把 join 查询部分移除 |
searchCount | boolean | true | 是否进行 count 查询,如果只想查询到列表不要查询总记录数,设置该参数为 false |
maxLimit | Long | 单页分页条数限制 | |
countId | String | xml 自定义 count 查询的 statementId 也可以不用指定在分页 statementId 后面加上 _mpCount 例如分页 selectPageById 指定 count 的查询 statementId 设置为 selectPageById_mpCount 即可默认找到该 SQL 执行 |
Page<Users> usersPage = new Page<>();
usersPage.setSize(2l);
IPage<Users> usersPage1 = usersMapper.selectPage(usersPage, null);
System.out.println("页面大小"+usersPage1.getSize());
System.out.println("当前页"+usersPage1.getCurrent());
System.out.println("数据总数"+usersPage1.getTotal());
System.out.println("总页数"+usersPage1.getPages());
System.out.println("当前页面数据"+usersPage1.getRecords());
Execute SQL:SELECT COUNT(*) AS total FROM users
Execute SQL:SELECT id,name,age,email FROM users LIMIT 2
页面大小2
当前页1
数据总数5
总页数3
当前页面数据[Users(id=3, name=Mike, age=18, email=test3@baomidou.com), Users(id=4, name=Sandy, age=18, email=test4@baomidou.com)]
7-逻辑删除
步骤 1: 配置com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig
- 例: application.yml
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
骤 2: 实体类字段上加上@TableLogic
注解
@TableLogic
private Integer deleted;
usersMapper.deleteById(3l);
UPDATE users SET deleted=1 WHERE id=3 AND deleted=0
可以看出添加了@TableLogic
注解之后执行删除方法,结果sql是修改并且加上了一个 AND deleted=0
8-关联查询分页
扫描mapper.xml文件
mybatis-plus:
# configuration:
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL到控制台
# global-config:
# banner: off # 关闭mybatisplus启动图标
mapper-locations: classpath:/mapper/*Mapper.xml
自定义sql
<mapper namespace="com.gcxy.mapper.UserMapper">
</resultMap>
<!-- <select id="selectOrders" resultType="orderVo"> -->
<!-- select o.order_id, o.user_id, o.goods_name, o.goods_price, u.name, u.age, u.gender -->
<!-- from t_order as o left join t_user as u on o.user_id = u.id -->
<!-- </select> -->
<select id="selectOrderPage" resultType="orderVo"> select o.order_id, o.user_id, o.goods_name, o.goods_price, u.name, u.age, u.gender from t_order as o left join t_user as u on o.user_id = u.id ${ew.customSqlSegment} </select>
</mapper>
// 关联分页查询
IPage<OrderVo> selectOrderPage(IPage<OrderVo> page, @Param(Constants.WRAPPER) QueryWrapper<OrderVo> wrapper);
请注意
@Param(Constants.WRAPPER) QueryWrapper wrapper
可以替换为QueryWrapper ew
// 多表关联查询
// 需求:假设前端需要展示数据:订单号、商品名称、商品价格、下单用户名、下单用户年龄、性别
// select o.order_id,o.user_id,o.goods_name,o.goods_price,u.name,u.age,u.gender from t_order as o left join t_user as u on o.user_id=u.id
List<OrderVo> orderVos = userMapper.selectOrders();
orderVos.forEach(System.out::println);
// 关联分页查询
//查询第一页,每页数据显示10条
Page<OrderVo> page = new Page<>(1,10);
// // 手动关闭sql优化,不然查询总数的时候只会查询主表
page.setOptimizeCountSql(false);
//
//组装查询条件 age = 30
QueryWrapper<OrderVo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("age",30);
//
IPage<OrderVo> page1 = userMapper.selectOrderPage(page,queryWrapper);
System.out.println("总记录数:" + page1.getTotal());
System.out.println("总共页数:" + page1.getPages());
System.out.println("当前页码:" + page1.getCurrent());
System.out.println("当前查询数据:" + page1.getRecords());