一、需求
表结构里面有两个固定字段,DATA_STATE 和 DELETE_MARKER
char(1) DATA_STATE 数据状态 (1正常 0逻辑删除)
char(1) DELETE_MARKER 删除标记 (0: 未删除,null:删除)
逻辑删除 DATA_STATE='0' 时,需要强制对对应的表字段(DELETE_MARKER)进行置空,
设置DELETE_MARKER=null。
二、方案
由于 DELETE_MARKER 字段是为了优化索引才加入表结构。系统中大量SQL语句,逻辑删除时,都只有 set data_state = '0',如果一个个修改,费事费力。
所以使用 Mybatis 拦截器来做,在SQL预编译的时候,拦截UPDATE类型SQL,判断是否 set data_state = '0' 如果是,修改SQL语句同步更新 delete_marker = null。
三、代码
package com.macrosoft.interceptor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.*;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.statement.update.UpdateSet;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.xmltags.OgnlCache;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* DELETE_MARKER mybatis拦截器
* 需求:
* DATA_STATE 数据状态 (1正常 0逻辑删除)
* DELETE_MARKER 删除标记 (0: 未删除,null:删除)
* 逻辑删除 DATA_STATE=0时,需要强制对对应的表字段(DELETE_MARKER)进行置空,
* 设置DELETE_MARKER=null
* 拦截UPDATE类型SQL,判断是否 update data_state=0
* 修改SQL语句同步更新delete_marker=null
* @Author : linzp
*/
@Slf4j
@Component
@ConditionalOnProperty(prefix = "delete_marker_intercept", value = "enable", havingValue = "true")
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class })})
public class DeleteMarkerInterceptor implements Interceptor {
private static final String LOGICAL_DELETION_STRING_VALUE = "0";
private static final String DATA_STATE_PROPERTY = "dataState";
private static final String DATA_STATE_FIELD_UPPERCASE = "DATA_STATE";
private static final String DATA_ST