参考链接:https://mp.baomidou.com/guide(官方文档)
https://www.cnblogs.com/l-y-h/p/12859477.html#_label2_0
https://zhuanlan.zhihu.com/p/127776877
本文档是对于官网文档学习的理解和补充
@TableId(value = "area_id", type = IdType.ASSIGN_ID)
private Integer areaId;//统一使用引用类型
(1)简介
上面介绍的 接口方法的参数中,会出现各种 wrapper,比如 queryWrapper、updateWrapper 等。wrapper 的作用就是用于定义各种各样的查询条件(where)。
Wrapper 条件构造抽象类
- AbstractWrapper 查询条件封装,用于生成 sql 中的 where 语句。
- QueryWrapper Entity 对象封装操作类,用于查询。
- UpdateWrapper Update 条件封装操作类,用于更新。
- AbstractLambdaWrapper 使用 Lambda 表达式封装 wrapper
- LambdaQueryWrapper 使用 Lambda 语法封装条件,用于查询。
- LambdaUpdateWrapper 使用 Lambda 语法封装条件,用于更新。
@Test
public void testQueryWrapper() {
// Step1:创建一个(对表user的) QueryWrapper 对象
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// Step2: 构造查询条件
queryWrapper
.select("id", "name", "age")
.eq("age", 20)
.like("name", "j");
//select id, name, age from user where age=20 and name like '%j%';
// Step3:执行查询
userService
.list(queryWrapper)
.forEach(System.out::println);
}
LambdaQueryWrapper 使用条件查询的参数是实体类的属性,QueryWrapper查询条件的参数是数据库中的字段
new LambdaQueryWrapper<Comment>().eq(Comment::getAppId,appId).notIn(Comment::getCommId,hotCommIdList).orderByDesc(Comment::getCommDate)
new QueryWrapper<Comment>().eq("app_id",appId).notIn("comm_id",hotCommIdList).orderByDesc("comm_date")
使用代码生成器生成的 mapper 接口中,其继承了 BaseMapper 接口。
而 BaseMapper 接口中封装了一系列 CRUD 常用操作,可以直接使用,而不用自定义 xml 与 sql 语句进行 CRUD 操作(当然根据实际开发需要,自定义 sql 还是有必要的)。
此处简单介绍一下 BaseMapper 接口中的常用方法。
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
【添加数据:(增)】
int insert(T entity); // 插入一条记录
注:
T 表示任意实体类型
entity 表示实体对象
【删除数据:(删)】
int deleteById(Serializable id); // 根据主键 ID 删除
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); // 根据 map 定义字段的条件删除
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper); // 根据实体类定义的 条件删除对象
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); // 进行批量删除
注:
id 表示 主键 ID
columnMap 表示表字段的 map 对象
wrapper 表示实体对象封装操作类,可以为 null。
idList 表示 主键 ID 集合(列表、数组),不能为 null 或 empty
【修改数据:(改)】
int updateById(@Param(Constants.ENTITY) T entity); // 根据 ID 修改实体对象。
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper); // 根据 updateWrapper 条件修改实体对象
注:
update 中的 entity 为 set 条件,可以为 null。
updateWrapper 表示实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
【查询数据:(查一条)】
T selectById(Serializable id); // 根据 主键 ID 查询数据
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 根据实体类封装对象 查询一条记录
【查询数据:(查多条)】
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); // 进行批量查询
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); // 根据表字段条件查询
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 entity 集合)
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 map 集合)
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(但只保存第一个字段的值)
【查询数据:(分页)】
<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 entity 集合),分页
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 map 集合),分页
【查询数据:(记录数)】
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询记录的总条数
注:
queryWrapper 表示实体对象封装操作类(可以为 null)
page 表示分页查询条件
LambdaQueryWrapper<Comment> commentLQWrapper = new LambdaQueryWrapper<Comment>();
int totalCount = commentDao.selectCount(commentLQWrapper.eq(Comment::getAppId,appId));
<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); // 查询所有记录(返回 entity 集合),分页
List<Comment> commentList = commentDao.selectPage(new Page<Comment>(curent, limit), new QueryWrapper<Comment>().eq("app_id", appId)).getRecords();
简介
使用 代码生成器 生成的 service 接口中,其继承了 IService 接口。
IService 内部进一步封装了 BaseMapper 接口的方法(当然也提供了更详细的方法)。
使用时,可以通过 生成的 mapper 类进行 CRUD 操作,也可以通过 生成的 service 的实现类进行 CRUD 操作。(当然,自定义代码执行也可)
此处简单介绍一下 IService 中封装的常用方法。
IService接口源码:
public interface IService<T> {
int DEFAULT_BATCH_SIZE = 1000;
//增
default boolean save(T entity) { return SqlHelper.retBool(this.getBaseMapper().insert(entity)); }
@Transactional( rollbackFor = {Exception.class} )
default boolean saveBatch( Collection<T> entityList) {return this.saveBatch(entityList, 1000); }
boolean saveBatch(Collection<T> entityList, int batchSize);
@Transactional( rollbackFor = {Exception.class} )
default boolean saveOrUpdateBatch(Collection<T> entityList) { return this.saveOrUpdateBatch(entityList, 1000); }
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
//删
default boolean removeById(Serializable id) { return SqlHelper.retBool(this.getBaseMapper().deleteById(id)); }
default boolean removeByMap(Map<String, Object> columnMap) {
Assert.notEmpty(columnMap, "error: columnMap must not be empty", new Object[0]);
return SqlHelper.retBool(this.getBaseMapper().deleteByMap(columnMap));
}
default boolean remove(Wrapper<T> queryWrapper) {
return SqlHelper.retBool(this.getBaseMapper().delete(queryWrapper));
}
default boolean removeByIds(Collection<? extends Serializable> idList) {
return CollectionUtils.isEmpty(idList) ? false : SqlHelper.retBool(this.getBaseMapper().deleteBatchIds(idList));
}
//改
default boolean updateById(T entity) { return SqlHelper.retBool(this.getBaseMapper().updateById(entity)); }
default boolean update(Wrapper<T> updateWrapper) { return this.update((Object)null, updateWrapper); }
default boolean update(T entity, Wrapper<T> updateWrapper) {
return SqlHelper.retBool(this.getBaseMapper().update(entity, updateWrapper));
}
@Transactional( rollbackFor = {Exception.class} )
default boolean updateBatchById(Collection<T> entityList) { return this.updateBatchById(entityList, 1000); }
boolean updateBatchById(Collection<T> entityList, int batchSize);
boolean saveOrUpdate(T entity);
//查
default T getById(Serializable id) { return this.getBaseMapper().selectById(id); }
default List<T> listByIds(Collection<? extends Serializable> idList) { return this.getBaseMapper().selectBatchIds(idList); }
default List<T> listByMap(Map<String, Object> columnMap) { return this.getBaseMapper().selectByMap(columnMap); }
default T getOne(Wrapper<T> queryWrapper) { return this.getOne(queryWrapper, true); }
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
Map<String, Object> getMap(Wrapper<T> queryWrapper);
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
default int count() {
return this.count(Wrappers.emptyWrapper());
}
default int count(Wrapper<T> queryWrapper) {
return SqlHelper.retCount(this.getBaseMapper().selectCount(queryWrapper));
}
default List<T> list(Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectList(queryWrapper);
}
default List<T> list() {
return this.list(Wrappers.emptyWrapper());
}
//查询(分页)
default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectPage(page, queryWrapper);
}
default <E extends IPage<T>> E page(E page) {
return this.page(page, Wrappers.emptyWrapper());
}
default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectMaps(queryWrapper);
}
default List<Map<String, Object>> listMaps() {
return this.listMaps(Wrappers.emptyWrapper());
}
default List<Object> listObjs() {
return this.listObjs(Function.identity());
}
default <V> List<V> listObjs(Function<? super Object, V> mapper) {
return this.listObjs(Wrappers.emptyWrapper(), mapper);
}
default List<Object> listObjs(Wrapper<T> queryWrapper) {
return this.listObjs(queryWrapper, Function.identity());
}
default <V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper) {
return (List)this.getBaseMapper().selectObjs(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
}
default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper) {
return this.getBaseMapper().selectMapsPage(page, queryWrapper);
}
default <E extends IPage<Map<String, Object>>> E pageMaps(E page) {
return this.pageMaps(page, Wrappers.emptyWrapper());
}
BaseMapper<T> getBaseMapper();
//链式调用
default QueryChainWrapper<T> query() {
return ChainWrappers.queryChain(this.getBaseMapper());
}
default LambdaQueryChainWrapper<T> lambdaQuery() {
return ChainWrappers.lambdaQueryChain(this.getBaseMapper());
}
default UpdateChainWrapper<T> update() {
return ChainWrappers.updateChain(this.getBaseMapper());
}
default LambdaUpdateChainWrapper<T> lambdaUpdate() {
return ChainWrappers.lambdaUpdateChain(this.getBaseMapper());
}
default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);
}
}
【添加数据:(增)】
default boolean save(T entity); // 调用 BaseMapper 的 insert 方法,用于添加一条数据。
boolean saveBatch(Collection<T> entityList, int batchSize); // 批量插入数据
注:
entityList 表示实体对象集合
batchSize 表示一次批量插入的数据量,默认为 1000
【添加或修改数据:(增或改)】
boolean saveOrUpdate(T entity); // id 若存在,则修改, id 不存在则新增数据
default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper); // 先根据条件尝试更新,然后再执行 saveOrUpdate 操作
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize); // 批量插入并修改数据
【删除数据:(删)】
default boolean removeById(Serializable id); // 调用 BaseMapper 的 deleteById 方法,根据 id 删除数据。
default boolean removeByMap(Map<String, Object> columnMap); // 调用 BaseMapper 的 deleteByMap 方法,根据 map 定义字段的条件删除
default boolean remove(Wrapper<T> queryWrapper); // 调用 BaseMapper 的 delete 方法,根据实体类定义的 条件删除对象。
default boolean removeByIds(Collection<? extends Serializable> idList); // 用 BaseMapper 的 deleteBatchIds 方法, 进行批量删除。
【修改数据:(改)】
default boolean updateById(T entity); // 调用 BaseMapper 的 updateById 方法,根据 ID 选择修改。
default boolean update(T entity, Wrapper<T> updateWrapper); // 调用 BaseMapper 的 update 方法,根据 updateWrapper 条件修改实体对象。
boolean updateBatchById(Collection<T> entityList, int batchSize); // 批量更新数据
【查找数据:(查)】
default T getById(Serializable id); // 调用 BaseMapper 的 selectById 方法,根据 主键 ID 返回数据。
default List<T> listByIds(Collection<? extends Serializable> idList); // 调用 BaseMapper 的 selectBatchIds 方法,批量查询数据。
default List<T> listByMap(Map<String, Object> columnMap); // 调用 BaseMapper 的 selectByMap 方法,根据表字段条件查询
default T getOne(Wrapper<T> queryWrapper); // 返回一条记录(实体类保存)。
Map<String, Object> getMap(Wrapper<T> queryWrapper); // 返回一条记录(map 保存)。
default int count(Wrapper<T> queryWrapper); // 根据条件返回 记录数。
default List<T> list(); // 返回所有数据。
default List<T> list(Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectList 方法,查询所有记录(返回 entity 集合)。
default List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectMaps 方法,查询所有记录(返回 map 集合)。
default List<Object> listObjs(); // 返回全部记录,但只返回第一个字段的值。
default <E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectPage 方法,分页查询
default <E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper); // 调用 BaseMapper 的 selectMapsPage 方法,分页查询
注:
get 用于返回一条记录。
list 用于返回多条记录。
count 用于返回记录总数。
page 用于分页查询。
【链式调用:】
default QueryChainWrapper<T> query(); // 普通链式查询
default LambdaQueryChainWrapper<T> lambdaQuery(); // 支持 Lambda 表达式的修改
default UpdateChainWrapper<T> update(); // 普通链式修改
default LambdaUpdateChainWrapper<T> lambdaUpdate(); // 支持 Lambda 表达式的修改
注:
query 表示查询
update 表示修改
Lambda 表示内部支持 Lambda 写法。
形如:
query().eq("column", value).one();
lambdaQuery().eq(Entity::getId, value).list();
update().eq("column", value).remove();
lambdaUpdate().eq(Entity::getId, value).update(entity);
需要引入依赖,然后编写bean(Spring boot方式)
PaginationInterceptor 源码
@Intercepts({@Signature( type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class} )})
public class PaginationInterceptor extends AbstractSqlParserHandler implements Interceptor {
protected static final Log logger = LogFactory.getLog(PaginationInterceptor.class);
protected ISqlParser countSqlParser;
protected boolean overflow = false;
protected long limit = 500L;
private DbType dbType;
private IDialect dialect;
/** @deprecated */
@Deprecated
protected String dialectType;
/** @deprecated */
@Deprecated
protected String dialectClazz;
public PaginationInterceptor() {
}
public static String concatOrderBy(String originalSql, IPage<?> page) {
if (CollectionUtils.isNotEmpty(page.orders())) {
try {
List<OrderItem> orderList = page.orders();
Select selectStatement = (Select)CCJSqlParserUtil.parse(originalSql);
List orderByElements;
List orderByElementsReturn;
if (selectStatement.getSelectBody() instanceof PlainSelect) {
PlainSelect plainSelect = (PlainSelect)selectStatement.getSelectBody();
orderByElements = plainSelect.getOrderByElements();
orderByElementsReturn = addOrderByElements(orderList, orderByElements);
plainSelect.setOrderByElements(orderByElementsReturn);
return plainSelect.toString();
}
if (selectStatement.getSelectBody() instanceof SetOperationList) {
SetOperationList setOperationList = (SetOperationList)selectStatement.getSelectBody();
orderByElements = setOperationList.getOrderByElements();
orderByElementsReturn = addOrderByElements(orderList, orderByElements);
setOperationList.setOrderByElements(orderByElementsReturn);
return setOperationList.toString();
}
if (selectStatement.getSelectBody() instanceof WithItem) {
return originalSql;
}
return originalSql;
} catch (JSQLParserException var7) {
logger.warn("failed to concat orderBy from IPage, exception=" + var7.getMessage());
}
}
return originalSql;
}
private static List<OrderByElement> addOrderByElements(List<OrderItem> orderList, List<OrderByElement> orderByElements) {
List<OrderByElement> orderByElements = CollectionUtils.isEmpty(orderByElements) ? new ArrayList(orderList.size()) : orderByElements;
List<OrderByElement> orderByElementList = (List)orderList.stream().filter((item) -> {
return StringUtils.isNotBlank(item.getColumn());
}).map((item) -> {
OrderByElement element = new OrderByElement();
element.setExpression(new Column(item.getColumn()));
element.setAsc(item.isAsc());
element.setAscDescPresent(true);
return element;
}).collect(Collectors.toList());
((List)orderByElements).addAll(orderByElementList);
return (List)orderByElements;
}
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler)PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
this.sqlParser(metaObject);
MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
if (SqlCommandType.SELECT == mappedStatement.getSqlCommandType() && StatementType.CALLABLE != mappedStatement.getStatementType()) {
BoundSql boundSql = (BoundSql)metaObject.getValue("delegate.boundSql");
Object paramObj = boundSql.getParameterObject();
IPage<?> page = null;
if (paramObj instanceof IPage) {
page = (IPage)paramObj;
} else if (paramObj instanceof Map) {
Iterator var8 = ((Map)paramObj).values().iterator();
while(var8.hasNext()) {
Object arg = var8.next();
if (arg instanceof IPage) {
page = (IPage)arg;
break;
}
}
}
if (null != page && page.getSize() >= 0L) {
if (this.limit > 0L && this.limit <= page.getSize()) {
this.handlerLimit(page);
}
String originalSql = boundSql.getSql();
Connection connection = (Connection)invocation.getArgs()[0];
if (page.isSearchCount() && !page.isHitCount()) {
SqlInfo sqlInfo = SqlParserUtils.getOptimizeCountSql(page.optimizeCountSql(), this.countSqlParser, originalSql);
this.queryTotal(sqlInfo.getSql(), mappedStatement, boundSql, page, connection);
if (page.getTotal() <= 0L) {
return null;
}
}
DbType dbType = (DbType)Optional.ofNullable(this.dbType).orElse(JdbcUtils.getDbType(connection.getMetaData().getURL()));
IDialect dialect = (IDialect)Optional.ofNullable(this.dialect).orElse(DialectFactory.getDialect(dbType));
String buildSql = concatOrderBy(originalSql, page);
DialectModel model = dialect.buildPaginationSql(buildSql, page.offset(), page.getSize());
Configuration configuration = mappedStatement.getConfiguration();
List<ParameterMapping> mappings = new ArrayList(boundSql.getParameterMappings());
Map<String, Object> additionalParameters = (Map)metaObject.getValue("delegate.boundSql.additionalParameters");
model.consumers(mappings, configuration, additionalParameters);
metaObject.setValue("delegate.boundSql.sql", model.getDialectSql());
metaObject.setValue("delegate.boundSql.parameterMappings", mappings);
return invocation.proceed();
} else {
return invocation.proceed();
}
} else {
return invocation.proceed();
}
}
protected void handlerLimit(IPage<?> page) {
page.setSize(this.limit);
}
protected void queryTotal(String sql, MappedStatement mappedStatement, BoundSql boundSql, IPage<?> page, Connection connection) {
try {
PreparedStatement statement = connection.prepareStatement(sql);
Throwable var7 = null;
try {
DefaultParameterHandler parameterHandler = new MybatisDefaultParameterHandler(mappedStatement, boundSql.getParameterObject(), boundSql);
parameterHandler.setParameters(statement);
long total = 0L;
ResultSet resultSet = statement.executeQuery();
Throwable var12 = null;
try {
if (resultSet.next()) {
total = resultSet.getLong(1);
}
} catch (Throwable var37) {
var12 = var37;
throw var37;
} finally {
if (resultSet != null) {
if (var12 != null) {
try {
resultSet.close();
} catch (Throwable var36) {
var12.addSuppressed(var36);
}
} else {
resultSet.close();
}
}
}
page.setTotal(total);
if (this.overflow && page.getCurrent() > page.getPages()) {
this.handlerOverflow(page);
}
} catch (Throwable var39) {
var7 = var39;
throw var39;
} finally {
if (statement != null) {
if (var7 != null) {
try {
statement.close();
} catch (Throwable var35) {
var7.addSuppressed(var35);
}
} else {
statement.close();
}
}
}
} catch (Exception var41) {
throw ExceptionUtils.mpe("Error: Method queryTotal execution error of sql : \n %s \n", var41, new Object[]{sql});
}
}
protected void handlerOverflow(IPage<?> page) {
page.setCurrent(1L);
}
public Object plugin(Object target) {
return target instanceof StatementHandler ? Plugin.wrap(target, this) : target;
}
。。。。set方法
}
IPage源码:
public interface IPage<T> extends Serializable {
/** @deprecated */
@Deprecated
default String[] descs() {
return null;
}
/** @deprecated */
@Deprecated
default String[] ascs() {
return null;
}
List<OrderItem> orders();
default Map<Object, Object> condition() {
return null;
}
default boolean optimizeCountSql() {
return true;
}
default boolean isSearchCount() {
return true;
}
default long offset() {
return this.getCurrent() > 0L ? (this.getCurrent() - 1L) * this.getSize() : 0L;
}
default long getPages() {
if (this.getSize() == 0L) {
return 0L;
} else {
long pages = this.getTotal() / this.getSize();
if (this.getTotal() % this.getSize() != 0L) {
++pages;
}
return pages;
}
}
default IPage<T> setPages(long pages) {
return this;
}
default void hitCount(boolean hit) {
}
default boolean isHitCount() {
return false;
}
List<T> getRecords();
IPage<T> setRecords(List<T> records);
long getTotal();
IPage<T> setTotal(long total);
long getSize();
IPage<T> setSize(long size);
long getCurrent();
IPage<T> setCurrent(long current);
default <R> IPage<R> convert(Function<? super T, ? extends R> mapper) {
List<R> collect = (List)this.getRecords().stream().map(mapper).collect(Collectors.toList());
return this.setRecords(collect);
}
}