Mybatis Plus核心功能
一,条件构造器
1.1 介绍
MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件。Wrapper 类允许开发者以链式调用的方式构造查询条件,无需编写繁琐的 SQL 语句,从而提高开发效率并减少 SQL 注入的风险。
在 MyBatis-Plus 中,Wrapper 类是构建查询和更新条件的核心工具。以下是主要的 Wrapper 类及其功能:
- AbstractWrapper:这是一个抽象基类,提供了所有 Wrapper 类共有的方法和属性。它定义了条件构造的基本逻辑,包括字段(column)、值(value)、操作符(condition)等。所有的 QueryWrapper、UpdateWrapper、LambdaQueryWrapper 和 LambdaUpdateWrapper 都继承自 AbstractWrapper。
- QueryWrapper:专门用于构造查询条件,支持基本的等于、不等于、大于、小于等各种常见操作。它允许你以链式调用的方式添加多个查询条件,并且可以组合使用
and
和or
逻辑。 - UpdateWrapper:用于构造更新条件,可以在更新数据时指定条件。与 QueryWrapper 类似,它也支持链式调用和逻辑组合。使用 UpdateWrapper 可以在不创建实体对象的情况下,直接设置更新字段和条件。
- LambdaQueryWrapper:这是一个基于 Lambda 表达式的查询条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性和可维护性,尤其是在字段名可能发生变化的情况下。
- LambdaUpdateWrapper:类似于 LambdaQueryWrapper,LambdaUpdateWrapper 是基于 Lambda 表达式的更新条件构造器。它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。
1.2 使用方法
@Test
public void testSelect() {
System.out.println(("----- selectAll method test ------"));
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","wdadwa");
List<User> userList = userMapper.selectList(wrapper);
userList.forEach(System.out::println);
}
上述构建了一个条件构造器,然后我们将条件构造器传入select即可实现条件查询
上述代码等效于:
select * from user where name='wdadwa'
1.2.1 MybatisPlus基础查询条件的方法
allEq
:允许我们通过一个Map
来设置多个字段的相等条件。eq
:用于设置单个字段的相等条件ne
:用于设置单个字段的不相等条件。gt
:用于设置单个字段的大于条件。ge
:用于设置单个字段的大于等于条件。It
:用于设置单个字段的小于条件Ie
:用于设置单个字段的小于等于条件。between
:用于设置单个字段的BETWEEN
条件。notBetween
:用于设置单个字段的NOT BETWEEN
条件。like
:用于设置单个字段的LIKE
条件。notLike
:用于设置单个字段的NOT LIKE
条件。likeLeft
:用于设置单个字段的左模糊匹配条件。likeRight
:用于设置单个字段的右模糊匹配条件。notLikeLeft
:用于设置单个字段的非左模糊匹配条件。notLikeRihgt
:用于设置单个字段的非右模糊匹配条件。isNull
:用于设置单个字段的IS NULL
条件。in
:用于设置单个字段的IN
条件,即字段的值在给定的集合中。notIn
:用于设置单个字段的NOT IN
条件,即字段的值不在给定的集合中。groupBy
:用于设置查询结果的分组条件。having
:它用于设置HAVING
子句,通常与GROUP BY
一起使用,用于对分组后的数据进行条件筛选。orderByAsc
:用于设置查询结果的升序排序条件orderByDesc
:用于设置查询结果的降序排序条件orderBy
:用于设置查询结果的排序条件。or
:用于在查询条件中添加OR
逻辑。and
:用于在查询条件中添加AND
逻辑。select
:用于设置查询的字段。通过调用select
方法,可以指定在查询结果中包含哪些字段,从而实现字段级别的查询定制。set
:用于设置更新语句中的SET
字段。通过调用set
方法,可以指定在更新操作中要修改的字段及其新值。setIncrBy
:允许你指定一个字段,并使其在数据库中的值增加指定的数值。setDecrBy
:允许你指定一个字段,并使其在数据库中的值减少指定的数值
1.2.2 LambdaWrapper和普通Wrapper的区别
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.lt("age", 18);
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.lt(User::getAge, 18);
一个通过方法引用的方式将字段传入,一个通过String硬编码将字段传入。
1.2.3 MybatisPlus构建复杂SQL
不推荐这种使用方式,MybatisPlus只推荐使用简单的单表crud,这种复杂的建议直接写到xml用Mybatis的方式来编写。本节了解即可。
举例:
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eqSql("id", "select MAX(id) from table");
等效于:
SELECT * FROM user WHERE id = (select MAX(id) from table)
所有的方法有:
inSql
:用于设置单个字段的IN
条件notInSql
:用于设置单个字段的NOT IN
条件eqSql
:允许你设置一个字段等于(EQ)某个 SQL 语句的结果gtSql
:允许你设置一个字段大于(GT)某个 SQL 语句的结果。geSql
:允许你设置一个字段大于等于(GE)某个 SQL 语句的结果。ItSql
:允许你设置一个字段小于(LT)某个 SQL 语句的结果。IeSql
:允许你设置一个字段小于等于(LE)某个 SQL 语句的结果。nested
:构建子查询apply
:允许你直接拼接 SQL 片段到查询条件中。last
:允许你直接在查询的最后添加一个 SQL 片段,而不受 MyBatis-Plus 的查询优化规则影响exists
:用于在查询中添加一个EXISTS
子查询notExists
:用于在查询中添加一个NOT EXISTS
子查询setSql
:允许你直接设置更新语句中的SET
部分 SQL。通
1.3 Wrappers
MyBatis-Plus 提供了 Wrappers
类,它是一个静态工厂类,用于快速创建 QueryWrapper
、UpdateWrapper
、LambdaQueryWrapper
和 LambdaUpdateWrapper
的实例。
使用 Wrappers
可以减少代码量,提高开发效率。
举例:
// 创建 QueryWrapper
QueryWrapper<User> queryWrapper = Wrappers.query();
queryWrapper.eq("name", "张三");
// 创建 LambdaQueryWrapper
LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
lambdaQueryWrapper.eq(User::getName, "张三");
// 创建 UpdateWrapper
UpdateWrapper<User> updateWrapper = Wrappers.update();
updateWrapper.set("name", "李四");
// 创建 LambdaUpdateWrapper
LambdaUpdateWrapper<User> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
lambdaUpdateWrapper.set(User::getName, "李四");
1.4 注意点
通过使用 MyBatis-Plus 的 Wrappers 条件构造器,开发者可以更加高效地构建复杂的数据库查询条件,同时保持代码的简洁性和安全性。
- 在使用 Wrapper 时,尽量使用 Lambda 表达式来避免硬编码字段名,这样可以提高代码的可读性和可维护性。Wrapper 支持链式调用,可以组合多个条件,如 and、or 等逻辑操作符。
- 在更新操作中使用 UpdateWrapper 或 LambdaUpdateWrapper 时,可以省略实体对象,直接在 Wrapper 中设置更新字段。
- 注意 Wrapper 的线程安全性,通常在每次使用时创建新的 Wrapper 实例。
- 在使用 MyBatis-Plus 的 Wrapper 时,应避免将前端动态参数直接拼接到 SQL 片段中,以防止 SQL 注入攻击。MyBatis-Plus 提供了安全的参数绑定方式,如使用 eq、apply 等方法,它们会自动处理参数绑定,避免 SQL 注入风险。
- 不推荐在MybatisPlus构建过于复杂的SQL,不便于维护。
- 每个方法的具体使用可以看官方文档:https://baomidou.com/guides/wrapper/#功能详解
二,自定义SQL
我们可以用MyBatisPlus的Wrapper来构建复杂Where条件,然后自己定义SQL语句中剩下的部分:
三,Service接口
如下图,我们的接口要继承IService接口,我们的实现类要继承ServiceImpl然后实现自己的接口。
IService 是 MyBatis-Plus 提供的一个通用 Service 层接口,它封装了常见的 CRUD 操作,包括插入、删除、查询和分页等。通过继承 IService 接口,可以快速实现对数据库的基本操作,同时保持代码的简洁性和可维护性。
IService 接口中的方法命名遵循了一定的规范,如 get 用于查询单行,remove 用于删除,list 用于查询集合,page 用于分页查询,这样可以避免与 Mapper 层的方法混淆。
3.1 配置方法
-
接口
public interface IDemoService extends IService<User> { }
-
实现类
@Service public class DemoServiceImpl extends ServiceImpl<UserMapper, User> implements IDemoService { }
两个泛型,一个是Mapper接口,一个是User类
3.2 save
功能描述: 插入记录,根据实体对象的字段进行策略性插入。
返回值: boolean,表示插入操作是否成功
参数说明:
entity
:实体类对象entityList
:实体类集合对象batchSize
:插入批次数量
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)(指定批次大小)
boolean saveBatch(Collection<T> entityList, int batchSize);
3.3 saveOrUpdate
功能描述: 根据实体对象的主键 ID 进行判断,存在则更新记录,否则插入记录。
返回值: boolean,表示插入或更新操作是否成功。
参数说明:
entity
:实体类对象updateWrapper
:实体对象封装操作类 UpdateWrapperentityList
:实体类集合对象batchSize
:插入批次数量
// 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);
3.4 remove
功能描述: 通过指定条件删除符合条件的记录。
返回值: boolean,表示删除操作是否成功。
参数说明:
queryWrapper
:实体包装类 QueryWrapperid
:主键 IDcolumnMap
:表字段 map 对象idList
:主键 ID 列表
// 根据 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);
3.5 update
功能描述: 通过指定条件更新符合条件的记录。
返回值: boolean,表示更新操作是否成功。
参数说明:
updateWrapper
:实体对象封装操作类 UpdateWrapperentity
:实体对象entityList
:实体对象集合batchSize
:更新批次数量
// 根据 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);
举例:
// 假设有一个 UpdateWrapper 对象,设置更新条件为 name = 'John Doe',更新字段为 email
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("name", "John Doe").set("email", "john.doe@newdomain.com");
boolean result = userService.update(updateWrapper); // 调用 update 方法
if (result) {
System.out.println("Record updated successfully.");
} else {
System.out.println("Failed to update record.");
}
生成的SQL:
UPDATE user SET email = 'john.doe@newdomain.com' WHERE name = 'John Doe'
3.6 get
功能描述: 根据指定条件查询符合条件的记录。
返回值: 查询结果,可能是实体对象、Map 对象或其他类型。
参数说明:
id
:主键IDqueryWrapper
:实体对象封装操作类 QueryWrapperthrowEx
:有多个 result 是否抛出异常entity
:实体对象mapper
:转换函数
// 根据 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);
3.7 list
功能描述: 查询符合条件的记录。
返回值: 查询结果,可能是实体对象、Map 对象或其他类型。
参数说明:
queryWrapper
:实体对象封装操作类 QueryWrapperidList
:主键 ID 列表columnMap
:表字段 map 对象mapper
:转换函数
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)(就是多个key=value条件)
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);
3.8 page
功能描述: 分页查询符合条件的记录。
返回值: 分页查询结果,包含记录列表和总记录数。
参数说明:
page
:翻页对象queryWrapper
:实体对象封装操作类 QueryWrapper
// 无条件分页查询
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);
举例:
// 假设要进行无条件的分页查询,每页显示10条记录,查询第1页
IPage<User> page = new Page<>(1, 10);
IPage<User> userPage = userService.page(page); // 调用 page 方法
List<User> userList = userPage.getRecords();
long total = userPage.getTotal();
System.out.println("Total users: " + total);
for (User user : userList) {
System.out.println("User: " + user);
}
生成的SQL:
SELECT * FROM user LIMIT 10 OFFSET 0
3.9 count
功能描述: 查询符合条件的记录总数。
返回值: 符合条件的记录总数。
参数说明:
queryWrapper
:实体对象封装操作类 QueryWrapper
// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);
//自3.4.3.2开始,返回值修改为long
// 查询总记录数
long count();
// 根据 Wrapper 条件,查询总记录数
long count(Wrapper<T> queryWrapper);
3.10 lambda方法
在上述方法中,我们条件查询都需要new一个Wrapper来进行设置条件,但是实际上在Service接口中已经帮我们定义了一个lambda方法来直接设置条件了。
用法:
@Override
public List<User> testLambda() {
return lambdaQuery()
.eq(User::getName, "张三")
.ge(User::getAge, 30)
.list();
}
除了lambdaQuery还有lambdaUpdate
,如果我们想调用mapper接口的BaseMapper的方法,我们直接调用baseMapper
即可,因为ServiceImpl已经自动注入了BaseMapper
四,Mapper接口
BaseMapper 是 Mybatis-Plus 提供的一个通用 Mapper 接口,它封装了一系列常用的数据库操作方法,包括增、删、改、查等。通过继承 BaseMapper,开发者可以快速地对数据库进行操作,而无需编写繁琐的 SQL 语句。
只需要在Mapper层基础BaseMapper接口即可。
4.1 insert
功能描述: 插入一条记录。
返回值: int,表示插入操作影响的行数,通常为 1,表示插入成功。
// 插入一条记录
int insert(T entity);
4.2 delete
功能描述: 删除符合条件的记录。
返回值: int,表示删除操作影响的行数,通常为 1,表示删除成功。
// 根据 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);
4.3 update
功能描述: 更新符合条件的记录。
返回值: int,表示更新操作影响的行数,通常为 1,表示更新成功。
参数说明:
entity
:实体对象 (set 条件值,可为 null)updateWrapper
:实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
4.4 select
功能描述: 查询符合条件的记录。
返回值: 查询结果,可能是实体对象、Map 对象或其他类型。
参数说明:
id
:主键 IDqueryWrapper
:实体对象封装操作类(可以为 null)idList
:主键 ID 列表(不能为 null 以及 empty)columnMap
:表字段 map 对象page
:分页查询条件(可以为 RowBounds.DEFAULT)
// 根据 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);