MP-通用Mapper
- 1、源码分析
一、通用Mapper
在MyBatis-Plus里面,可以实现对数据库的CRUD操作,官方对通用Mapper的解释如下说明:
通用 CRUD 封装BaseMapper (opens new window)接口,为 Mybatis-Plus 启动时自动解析实体表关系映射转换为 Mybatis 内部对象注入容器,
1、泛型 T 为任意实体对象
,
2、参数 Serializable 为任意类型主键 Mybatis-Plus 不推荐使用复合主键约定每一张表都有自己的唯一 id 主键
,
3、对象 Wrapper 为 条件构造器
这张图的大致含义就是 MyBatis-PLUS利用注解,核心模块和生成器等组件,来完成对实体的扫描,自动映射解析实体对象,完成表名与列名的对应关系。通过封装的SQL语句,最终完成 CRUD操作。
二、使用方式
在Mapper的接口上需要继承一个BaseMapper的接口,其泛型为操作的数据库表对应的pojo类。
@Repository("userMapper")
public interface UserMapper extends BaseMapper<User>{
}
1、源码分析
BaseMapper的源码如下所示,
public interface BaseMapper<T> extends Mapper<T> {
/**
* 插入一条记录
*
* @param entity 实体对象
*/
int insert(T entity);
/**
* 根据 ID 删除
*
* @param id 主键ID
*/
int deleteById(Serializable id);
/**
* 根据实体(ID)删除
*
* @param entity 实体对象
* @since 3.4.4
*/
int deleteById(T entity);
/**
* 根据 columnMap 条件,删除记录
*
* @param columnMap 表字段 map 对象
*/
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* 根据 entity 条件,删除记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 删除(根据ID或实体 批量删除)
*
* @param idList 主键ID列表或实体列表(不能为 null 以及 empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<?> idList);
/**
* 根据 ID 修改
*
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);
/**
* 根据 whereEntity 条件,更新记录
*
* @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
/**
* 根据 ID 查询
*
* @param id 主键ID
*/
T selectById(Serializable id);
/**
* 查询(根据ID 批量查询)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
/**
* 查询(根据 columnMap 条件)
*
* @param columnMap 表字段 map 对象
*/
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* 根据 entity 条件,查询一条记录
* <p>查询一条记录,例如 qw.last("limit 1") 限制取一条记录, 注意:多条数据会报异常</p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
default T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {
List<T> ts = this.selectList(queryWrapper);
if (CollectionUtils.isNotEmpty(ts)) {
if (ts.size() != 1) {
throw ExceptionUtils.mpe("One record is expected, but the query result is multiple records");
}
return ts.get(0);
}
return null;
}
/**
* 根据 Wrapper 条件,判断是否存在记录
*
* @param queryWrapper 实体对象封装操作类
* @return
*/
default boolean exists(Wrapper<T> queryWrapper) {
Long count = this.selectCount(queryWrapper);
return null != count && count > 0;
}
/**
* 根据 Wrapper 条件,查询总记录数
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Long selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
* <p>注意: 只返回第一个字段的值</p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
<P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
*/
<P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
1️⃣Insert 插入方法
参数说明:
类型 | 参数名 | 描述 |
T | Entity | 实体对象 |
案例演示:
@Test
public void test2() {
// 新增用户信息 INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
User user = new User("joker",23,"[email protected]");
int insert = userMapper.insert(user);
System.out.println("成功插入"+insert+"条数据");
// 在MyBatis里默认是使用雪花算法创建id 不会默认使用数据库里面的自增主键
System.out.println("id:"+user.getId());
}
注意:如果未设置主键,MyBatis-plus则会使用雪花算法自动生成一个随机的Long型的的主键
2️⃣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 | wrapper | 实体对象封装操作类(可以为 null) |
Collection<? extends Serializable> | idList | 主键 ID 列表(不能为 null 以及 empty) |
Serializable | id | 主键 ID |
Map<String, Object> | columnMap | 表字段 map 对象 |
案例演示:
1、delete
@Test
public void test() {
// 根据 entity 条件,删除记录
//int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
User user = new User();
user.setId(13L);
Wrapper<User> wrapper = new UpdateWrapper<>(user);
int delete = userMapper.delete(wrapper);
System.out.println("删除了"+delete+"条数据");
}
2、deleteBatchIds:
@Test
public void test5() {
// 批量删除 DELETE FROM user WHERE id IN ( ? , ? )
Collection<Long> ids = new ArrayList<>();
ids.add(5L);
ids.add(2L);
int deleteBatchIds = userMapper.deleteBatchIds(ids);
System.out.println("删除了"+deleteBatchIds+"条数据");
}
3、deleteById
@Test
public void test3() {
// 根据id删除 DELETE FROM user WHERE id=?
int deleteById = userMapper.deleteById(1529380500983910401L);
System.out.println("成功删除"+deleteById);
}
4、deleteByMap
@Test
public void test4() {
// 根据条件删除数据 可以删除多个 DELETE FROM user WHERE name = ? AND age = ?
Map<String, Object> map = new HashMap<>();
map.put("name", "张三");
map.put("age", 23);
int deleteByMap = userMapper.deleteByMap(map);
System.out.println("删除了"+deleteByMap);
}
3️⃣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 | updateWrapper | 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) |
案例演示:
1、Update
@Test
public void testupdate() {
// 根据id修改数据 UPDATE user SET name=?, age=?, email=? WHERE id=?
User user = new User(1L,"koppy",25,"[email protected]");
User wrapperUser = new User();
wrapperUser.setId(1L);
Wrapper<User> wrapper = new UpdateWrapper<>(wrapperUser);
int updateById = userMapper.update(user, wrapper);
System.out.println("修改了"+updateById+"条数据");
}
2、updateById
@Test
public void test6() {
// 根据id修改数据 UPDATE user SET name=?, age=?, email=? WHERE id=?
User user = new User(1L,"koppy",45,"[email protected]");
int updateById = userMapper.updateById(user);
System.out.println("修改了"+updateById+"条数据");
}
4️⃣ 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 | queryWrapper | 实体对象封装操作类(可以为 null) |
Collection<? extends Serializable> | idList | 主键 ID 列表(不能为 null 以及 empty) |
Map<String, Object> | columnMap | 表字段 map 对象 |
IPage | page | 分页查询条件(可以为 RowBounds.DEFAULT) |
案例演示:
1、selectById
@Test
public void testSelect() {
User user = userMapper.selectById(1L);
System.out.println(user);
}
2、selectOne
@Test
public void TestSelectOne() {
User user =new User();
user.setAge(18);
Wrapper<User> queWrapper =new QueryWrapper<>(user);
User selectOne = userMapper.selectOne(queWrapper);
System.out.println(selectOne);
}
注意:在使用SelectOne的方法的时候,需要注意的是!!!selectOne中方法如果查出多条数据,则会抛出一个警告,但是不会报错,原因就是SelectOne的底层中,对查询结果进行了一个判断,如果将结果>1则会抛出warn,否则会返回第一个查询结果
selectOne的底层源码:
/**
* 根据 entity 条件,查询一条记录
* <p>查询一条记录,例如 qw.last("limit 1") 限制取一条记录, 注意:多条数据会报异常</p>
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
default T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {
List<T> ts = this.selectList(queryWrapper);
if (CollectionUtils.isNotEmpty(ts)) {
if (ts.size() != 1) {
throw ExceptionUtils.mpe("One record is expected, but the query result is multiple records");
}
return ts.get(0);
}
return null;
}
**还要额外说明一点:我用的是MP的最新版本,不会像网上说的抛出警告,可能旧版本会吧,这个还需要看源码
3、selectByPage 不带条件的查询
@Test
public void selectByPage() {
Page<User> page = new Page<>();
page.setCurrent(1);
page.setSize(5);
User user = new User();
user.setAge(15);
Wrapper<User> wrapper =new QueryWrapper<>();
Page<User> page2 = userMapper.selectPage(page, null);
List<User> list = page2.getRecords();
for (User user2 : list) {
System.out.println(user2);
}
}
selectMapsPage带条件的查询
@Test
public void testSelectMapsPage() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 返回指定列,这里是数据库的字段,而不是实体类的属性
queryWrapper.select("id", "name", "age", "email");
Map<String, Object> paramMaps = new HashMap<>();
paramMaps.put("age",21);
queryWrapper.allEq(paramMaps);
Page<Map<String, Object>> page = new Page<>(1, 5);
// 第1个参数:分页参数 第2个参数:条件查询包装参数——指定了返回哪些列
Page<Map<String, Object>> pageParam = userMapper.selectMapsPage(page, queryWrapper);
List<Map<String, Object>> records = pageParam.getRecords();
records.forEach(System.out::println);
System.out.println("总页数:"+pageParam.getPages()); // 总页数
System.out.println("总记录数:"+pageParam.getTotal()); // 总记录数
System.out.println("当前页码:"+pageParam.getCurrent()); // 当前页码
System.out.println("每页记录数:"+pageParam.getSize()); // 每页记录数
System.out.println("是否有下一页:"+pageParam.hasNext()); // 是否有下一页
System.out.println("是否有上一页"+pageParam.hasPrevious()); // 是否有上一页
}