MyBatis-Plus原本是提供了逻辑删除的功能。
但如果在xml中直接写sql,它的逻辑删除是未生效的。
网上看了下,未找到这一解决方案…
下面我们来自定义一个简单的逻辑删除插件来实现这一功能^_^
LogicDeleteInterceptor
@Slf4j
@AllArgsConstructor
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class LogicDeleteInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
// 判断是不是SELECT操作 不是直接过滤
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
return invocation.proceed();
}
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
// 执行的SQL语句
String originalSql = boundSql.getSql();
// SQL语句的参数
Object parameterObject = boundSql.getParameterObject();
String finalSql = this.handleSql(originalSql);
// System.err.println("逻辑删除处理过后的SQL: \n" + finalSql);
metaObject.setValue("delegate.boundSql.sql", finalSql);
return invocation.proceed();
}
/**
* 改写SQL
* {@link com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor}
*
* @param originalSql 执行的SQL语句
* @return 处理后的SQL
* @author zhengqingya
* @date 2022/1/13 10:43
*/
private String handleSql(String originalSql) throws JSQLParserException {
CCJSqlParserManager parserManager = new CCJSqlParserManager();
Select select = (Select) parserManager.parse(new StringReader(originalSql));
SelectBody selectBody = select.getSelectBody();
if (selectBody instanceof PlainSelect) {
this.setWhere((PlainSelect) selectBody);
} else if (selectBody instanceof SetOperationList) {
SetOperationList setOperationList = (SetOperationList) selectBody;
List<SelectBody> selectBodyList = setOperationList.getSelects();
selectBodyList.forEach(s -> this.setWhere((PlainSelect) s));
}
return select.toString();
}
/**
* 设置 where 条件 -- 使用CCJSqlParser将原SQL进行解析并改写
* @param plainSelect 查询对象
*/
@SneakyThrows(Exception.class)
protected void setWhere(PlainSelect plainSelect) {
Table fromItem = (Table) plainSelect.getFromItem();
// 有别名用别名,无别名用表名,防止字段冲突报错
Alias fromItemAlias = fromItem.getAlias();
String originalTableName = fromItem.getName();
String mainTableName = fromItemAlias == null ? originalTableName : fromItemAlias.getName();
// 判断是否需要逻辑删除,如果不需要直接过滤
if (!MybatisPlusConfig.LOGIC_DELETE_TABLE.contains(originalTableName)) {
return;
}
// 构建子查询 -- 逻辑删除
String dataSql = mainTableName + ".is_deleted = 0";
if (plainSelect.getWhere() == null) {
plainSelect.setWhere(CCJSqlParserUtil.parseCondExpression(dataSql));
} else {
plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), CCJSqlParserUtil.parseCondExpression(dataSql)));
}
}
/**
* 生成拦截对象的代理
* @param target 目标对象
* @return 代理对象
*/
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
return target;
}
/**
* mybatis配置的属性
* @param properties mybatis配置的属性
*/
@Override
public void setProperties(Properties properties) {}
}
public static Set<String> LOGIC_DELETE_TABLE = new HashSet<>();
static {
LOGIC_DELETE_TABLE.add("t_demo");
}
@Bean
@ConditionalOnMissingBean
public LogicDeleteInterceptor logicDeleteInterceptor() {
return new LogicDeleteInterceptor();
}
可以看见已经自动加上了is_deleted = 0
https://gitee.com/zhengqingya/small-tools
今日分享语句:
坚定自己想要的。