一.逻辑删除
我们在生产时一般不会真正的删除数据,所以一般会采用逻辑删除的手段来达到目的。只需要在引入mybatis-plus之后在实体类中使用@TableLogic即可。
0代表未删除,1代表已删除。如下图:
@TableLogic(value = "0", delval = "1")
private Boolean deleted = false;
这样在调用mybatis-plus的删除方法时,就不会从库里删除数据,只会给deleted字段赋值1。这个时候在调用mybatis-plus的查询方法时,会自动过滤掉deleted字段值为1的数据。这种写法好处不言而喻,不用我们每次手动逻辑删除,手动过滤查询。
二.填充公共字段
在日常开发中我们会把一些公共字段抽取出来放到一个父类中,然而我们不可能在每个方法中都手动给公共字段赋值。这时候我们就可以用到mybatis-plus提供的@TableField注解。
例如给创建者,修改者,创建时间,修改时间这些公共字段填充值时就可以使用,用法如下
@TableField(fill = FieldFill.INSERT)
private Long createdBy;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updatedBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createdAt;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updatedAt;
我们来看下FieldFill各个值的意义,下面是官方代码可以看到写的很清楚,意思就是我们在调用mybatis-plus的一些方法时就会按照下面的逻辑填充值。
有些同学可能会好奇,框架怎么知道创建者,修改者这些字段值的呢,这个时候需要我们手动创建一个类实现MetaObjectHandler。
代码如下:
@Component
public class MetaHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createdAt", LocalDateTime.now(), metaObject);
this.setFieldValByName("updatedAt", LocalDateTime.now(), metaObject);
this.setFieldValByName("createdBy", Tools.getCurrentUserId(), metaObject);
this.setFieldValByName("updatedBy", Tools.getCurrentUserId(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updatedAt", LocalDateTime.now(), metaObject);
this.setFieldValByName("updatedBy", Tools.getCurrentUserId(), metaObject);
}
}
可以看到我们在这里告诉了mybatis-plus如何取值,其中Tools.getCurrentUserId()是我自己封装的方法,你们可以根据自己项目的情况取值。
三.逻辑删除如何实现填充公共字段
这时候我们会遇到一个问题,那就是我们在调用mybatis-plus下面这个删除方法的时候框架是没有填充公共字段的。
那我们如何解决呢,在mybatis的较新版本中(since 3.4.4)提供了下面这个方法,可以填充公共字段。
这时候可能还有疑问,那就是我们批量删除的时候怎么办呢,我们可以手动实现一个方法在批量删除的时候填充公共字段,我们写一个公共的MyBaseMapper继承BaseMapper,然后定义一个deleteBatchIdsWithFill方法。后面各个业务的mapper可以通过继承MyBaseMapper来使用。
public interface MyBaseMapper<T> extends BaseMapper<T> {
/**
* 批量逻辑删除
*
* @param entity
* @param idList
* @return
*/
int deleteBatchIdsWithFill(@Param(Constants.ENTITY) T entity, @Param(Constants.COLL) Collection<? extends Serializable> idList);
}
我们光定义一个方法还不行,还要实现逻辑,我们需要建一个类去继承AbstractMethod,在这个类中实现相关逻辑。
public class LogicDeleteBatchIdsWithFill extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql;
SqlMethod sqlMethod = SqlMethod.LOGIC_DELETE_BATCH_BY_IDS;
List<TableFieldInfo> fieldInfos = tableInfo.getFieldList().stream().filter(TableFieldInfo::isWithUpdateFill)
.collect(toList());
String sqlSet = "SET " + fieldInfos.stream().map(i -> i.getSqlSet(ENTITY_DOT)).collect(joining(EMPTY))
+ tableInfo.getLogicDeleteSql(false, false);
if (CollectionUtils.isNotEmpty(fieldInfos)) {
sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), sqlSet, tableInfo.getKeyColumn(),
SqlScriptUtils.convertForeach("#{item}", COLLECTION, null, "item", COMMA),
tableInfo.getLogicDeleteSql(true, true));
} else {
sql = String.format(sqlMethod.getSql(), tableInfo.getTableName(), sqlLogicSet(tableInfo),
tableInfo.getKeyColumn(),
SqlScriptUtils.convertForeach("#{item}", COLLECTION, null, "item", COMMA),
tableInfo.getLogicDeleteSql(true, true));
}
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, Object.class);
return addUpdateMappedStatement(mapperClass, modelClass, getMethod(sqlMethod), sqlSource);
}
@Override
public String getMethod(SqlMethod sqlMethod) {
return "deleteBatchIdsWithFill";
}
}
再自定义一个sql注入器继承DefaultSqlInjector,把logicDeleteBatchIdsWithFill()方法加入进去就大功告成。
public class CustomSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
methodList.add(new LogicDeleteBatchIdsWithFill());
return methodList;
}
}
后面在批量删除的时候直接调用logicDeleteBatchIdsWithFill()即可实现自动填充公共字段的逻辑,不需要费事费力的手动实现。
四.总结
如有错误之处,欢迎指正。如有疑问,欢迎讨论。