Skip to content

运行时动态修改SQL

装饰器模式

java
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

public abstract class AbstractConnection implements Connection {
    protected final Connection delegate;

    public AbstractConnection(Connection delegate) {
        this.delegate = delegate;
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        PreparedStatement ps = this.delegate.prepareStatement(sql);
        return ps;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        PreparedStatement ps = this.delegate.prepareStatement(sql, resultSetType, resultSetConcurrency);
        return ps;
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        PreparedStatement ps = this.delegate.prepareStatement(sql, autoGeneratedKeys);
        return ps;
    }

    // 其它方法
    @Override
    public Statement createStatement() throws SQLException {
        Statement s = this.delegate.createStatement();
        return s;
    }

    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        CallableStatement cs = this.delegate.prepareCall(sql);
        return cs;
    }

    @Override
    public String nativeSQL(String sql) throws SQLException {
        String str = this.delegate.nativeSQL(sql);
        return str;
    }

    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {
        this.delegate.setAutoCommit(autoCommit);
    }

    @Override
    public boolean getAutoCommit() throws SQLException {
        return this.delegate.getAutoCommit();
    }

    @Override
    public void commit() throws SQLException {
        this.delegate.commit();
    }

    @Override
    public void rollback() throws SQLException {
        this.delegate.rollback();
    }

    @Override
    public void close() throws SQLException {
        this.delegate.close();
    }

    @Override
    public boolean isClosed() throws SQLException {
        return this.delegate.isClosed();
    }

    @Override
    public DatabaseMetaData getMetaData() throws SQLException {
        return this.delegate.getMetaData();
    }

    @Override
    public void setReadOnly(boolean readOnly) throws SQLException {
        this.delegate.setReadOnly(readOnly);

    }

    @Override
    public boolean isReadOnly() throws SQLException {
        return this.delegate.isReadOnly();
    }

    @Override
    public void setCatalog(String catalog) throws SQLException {
        this.delegate.setCatalog(catalog);

    }

    @Override
    public String getCatalog() throws SQLException {
        return this.delegate.getCatalog();
    }

    @Override
    public void setTransactionIsolation(int level) throws SQLException {
        this.delegate.setTransactionIsolation(level);
    }

    @Override
    public int getTransactionIsolation() throws SQLException {
        return this.delegate.getTransactionIsolation();
    }

    @Override
    public SQLWarning getWarnings() throws SQLException {
        return this.delegate.getWarnings();
    }

    @Override
    public void clearWarnings() throws SQLException {
        this.delegate.clearWarnings();
    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
        return this.delegate.createStatement(resultSetType, resultSetConcurrency);
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return this.delegate.prepareCall(sql, resultSetType, resultSetConcurrency);
    }

    @Override
    public Map<String, Class<?>> getTypeMap() throws SQLException {
        return this.delegate.getTypeMap();
    }

    @Override
    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
        this.delegate.setTypeMap(map);
    }

    @Override
    public void setHoldability(int holdability) throws SQLException {
        this.delegate.setHoldability(holdability);
    }

    @Override
    public int getHoldability() throws SQLException {
        return this.delegate.getHoldability();
    }

    @Override
    public Savepoint setSavepoint() throws SQLException {
        return this.delegate.setSavepoint();
    }

    @Override
    public Savepoint setSavepoint(String name) throws SQLException {
        return this.delegate.setSavepoint(name);
    }

    @Override
    public void rollback(Savepoint savepoint) throws SQLException {
        this.delegate.rollback();
    }

    @Override
    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
        this.delegate.releaseSavepoint(savepoint);
    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return this.delegate.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return this.delegate.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return this.delegate.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
        return this.delegate.prepareStatement(sql, columnIndexes);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
        return this.delegate.prepareStatement(sql, columnNames);
    }

    @Override
    public Clob createClob() throws SQLException {
        return this.delegate.createClob();
    }

    @Override
    public Blob createBlob() throws SQLException {
        return this.delegate.createBlob();
    }

    @Override
    public NClob createNClob() throws SQLException {
        return this.delegate.createNClob();
    }

    @Override
    public SQLXML createSQLXML() throws SQLException {
        return this.delegate.createSQLXML();
    }

    @Override
    public boolean isValid(int timeout) throws SQLException {
        return this.delegate.isValid(timeout);
    }

    @Override
    public void setClientInfo(String name, String value) throws SQLClientInfoException {
        this.delegate.setClientInfo(name, value);
    }

    @Override
    public void setClientInfo(Properties properties) throws SQLClientInfoException {
        this.delegate.setClientInfo(properties);
    }

    @Override
    public String getClientInfo(String name) throws SQLException {
        return this.delegate.getClientInfo(name);
    }

    @Override
    public Properties getClientInfo() throws SQLException {
        return this.delegate.getClientInfo();
    }

    @Override
    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
        return this.delegate.createArrayOf(typeName, elements);
    }

    @Override
    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
        return this.delegate.createStruct(typeName, attributes);
    }

    @Override
    public void setSchema(String schema) throws SQLException {
        this.delegate.setSchema(schema);
    }

    @Override
    public String getSchema() throws SQLException {
        return this.delegate.getSchema();
    }

    @Override
    public void abort(Executor executor) throws SQLException {
        this.delegate.abort(executor);
    }

    @Override
    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
        this.delegate.setNetworkTimeout(executor, milliseconds);
    }

    @Override
    public int getNetworkTimeout() throws SQLException {
        return this.delegate.getNetworkTimeout();
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return this.delegate.unwrap(iface);
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return this.delegate.isWrapperFor(iface);
    }
}
java
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class PackConnection extends AbstractConnection {
    public PackConnection(Connection delegate) {
        super(delegate);
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        sql = ModifyExecuteSQL.modifySQL(sql);
        System.err.printf("\033[32m执行SQL: %s%n\033[30m", sql);
        PreparedStatement ps = this.delegate.prepareStatement(sql);
        return PreparedStatementProxyCreator.createProxy(this.getClass().getClassLoader(), ps);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        sql = ModifyExecuteSQL.modifySQL(sql);
        System.err.printf("\033[32m执行SQL: %s%n\033[30m", sql);
        PreparedStatement ps = this.delegate.prepareStatement(sql, resultSetType, resultSetConcurrency);
        return PreparedStatementProxyCreator.createProxy(this.getClass().getClassLoader(), ps);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        sql = ModifyExecuteSQL.modifySQL(sql);
        System.err.printf("\033[32m执行SQL: %s%n\033[30m", sql);
        PreparedStatement ps = this.delegate.prepareStatement(sql, autoGeneratedKeys);
        return PreparedStatementProxyCreator.createProxy(this.getClass().getClassLoader(), ps);
    }

}

动态代理模式

java
import java.lang.reflect.Proxy;
import java.sql.PreparedStatement;

public class PreparedStatementProxyCreator {

    public static PreparedStatement createProxy(ClassLoader classLoader, PreparedStatement ps) {
        // 定义代理类的加载器 | 指定代理类要实现的接口列表 | 定义代理对象的方法拦截逻辑
        Object proxy = Proxy.newProxyInstance(classLoader, new Class<?>[]{PreparedStatement.class}, new PreparedStatementHandler(ps));
        return (PreparedStatement) proxy;
    }

}
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;

public class PreparedStatementHandler implements InvocationHandler {
    private final PreparedStatement delegate;

    public PreparedStatementHandler(PreparedStatement delegate) {
        this.delegate = delegate;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 如果你需要对参数进行处理,那么你可以在这里进行
        if (method.getName().equals("setString")) {
            // ... 进行数据处理
        }
        return method.invoke(this.delegate, args);
    }
}

Spring AOP

java
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import javax.sql.DataSource;
import java.lang.reflect.Method;

public class DataSourceInterceptor implements MethodInterceptor {
    private final DataSource targetDataSource;

    public DataSourceInterceptor(DataSource targetDataSource) {
        this.targetDataSource = targetDataSource;
    }

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        // 当调用的 getConnection 方法时,我们直接通过 PackConnection
        // 包装原始的 Connection 对象(真正工作的还是原始的那个 Connection)
        if ("getConnection".equals(method.getName())) {
            return new PackConnection(this.targetDataSource.getConnection());
        }
        return invocation.proceed();
    }
}

Bean 后置处理器

自动代理 DataSource Bean

java
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;

@Component
public class DataSourceBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 如果是数据源对象(不管你用的什么连接池)
        if (bean instanceof DataSource dataSource) {
            // 创建代理对象
            ProxyFactory factory = new ProxyFactory(bean);
            factory.setProxyTargetClass(true); // 强制使用CGLIB代理(支持类代理
            factory.addAdvice(new DataSourceInterceptor(dataSource)); // 添加拦截逻辑
            return factory.getProxy(); // 返回代理对象
        }
        return bean; // 非DataSource类型,直接返回原Bean
    }
}

工具类查询语句加上 deleted = 0

java
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.PlainSelect;

public class ModifyExecuteSQL {

    /**
     * 修改SQL语句,自动添加软删除条件
     *
     * @param sqlStr 原始SQL语句
     * @return 修改后的SQL语句,如果解析失败则返回原SQL
     */
    public static String modifySQL(String sqlStr) {
        try {
            Statement statement = parseSQL(sqlStr);
            if (!(statement instanceof PlainSelect)) {
                return sqlStr;
            }

            PlainSelect select = (PlainSelect) statement;
            addSoftDeleteCondition(select);
            return select.toString();

        } catch (JSQLParserException e) {
            logParseError(sqlStr, e);
            return sqlStr;
        }
    }

    /**
     * 解析SQL语句
     */
    private static Statement parseSQL(String sqlStr) throws JSQLParserException {
        return CCJSqlParserUtil.parse(sqlStr);
    }

    /**
     * 添加软删除条件(deleted = 0)
     */
    private static void addSoftDeleteCondition(PlainSelect select) {
        String columnName = buildSoftDeleteColumnName(select);
        Expression newCondition = createSoftDeleteCondition(columnName);
        updateWhereClause(select, newCondition);
    }

    /**
     * 更新WHERE子句,添加新条件
     */
    private static void updateWhereClause(PlainSelect select, Expression newCondition) {
        Expression where = select.getWhere();

        if (where == null) {
            select.setWhere(newCondition);
        } else {
            select.setWhere(new AndExpression(where, newCondition));
        }
    }

    /**
     * 构建软删除列名(带表别名或表名)
     */
    private static String buildSoftDeleteColumnName(PlainSelect select) {
        FromItem fromItem = select.getFromItem();

        // 处理表别名
        if (fromItem.getAlias() != null) {
            return fromItem.getAlias().getName() + ".deleted";
        }

        // 处理表名(无别名情况)
        if (fromItem instanceof Table) {
            return ((Table) fromItem).getName() + ".deleted";
        }

        // 子查询或其他复杂情况,直接使用deleted
        return "deleted";
    }

    /**
     * 创建软删除条件表达式(deleted = 0)
     */
    private static Expression createSoftDeleteCondition(String columnName) {
        Column column = new Column(columnName);
        return new EqualsTo(column, new LongValue(0));
    }

    /**
     * 记录解析错误日志
     */
    private static void logParseError(String sqlStr, Exception e) {
        System.err.println("解析SQL【" + sqlStr + "】错误: " + e.getMessage());
    }

}

更新: 2025-07-19 10:55:25
原文: https://www.yuque.com/lsxxyg/sz/bcpiiinggadk0biv