自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MyBatis 攔截器,帶你輕松搞定數(shù)據(jù)脫敏!

數(shù)據(jù)庫 其他數(shù)據(jù)庫
MyBatis 攔截器是一種插件機制,用于在 MyBatis 執(zhí)行 SQL 語句時對其進行攔截、修改或增強。攔截器可以插入到 MyBatis 的執(zhí)行過程中的不同位置,從而實現(xiàn)自定義的行為,例如記錄日志、修改 SQL 查詢、增強性能等。

1. 引言

1.1 什么是 MyBatis 攔截器

MyBatis 攔截器是一種插件機制,用于在 MyBatis 執(zhí)行 SQL 語句時對其進行攔截、修改或增強。攔截器可以插入到 MyBatis 的執(zhí)行過程中的不同位置,從而實現(xiàn)自定義的行為,例如記錄日志、修改 SQL 查詢、增強性能等。

  • 定義:MyBatis 攔截器是一種自定義插件,可以通過它攔截 MyBatis 核心組件(如 Executor、StatementHandler、ParameterHandler、ResultSetHandler)的方法調(diào)用。通過攔截器,我們可以在不修改 MyBatis 源碼的情況下,改變其行為或增強其功能。
  • 功能:

修改 SQL 語句,例如根據(jù)某些業(yè)務(wù)規(guī)則動態(tài)拼接 SQL。

記錄 SQL 執(zhí)行日志、性能監(jiān)控,統(tǒng)計執(zhí)行時間等。

控制事務(wù)或?qū)崿F(xiàn)緩存邏輯等。

1.2 為什么使用攔截器

使用 MyBatis 攔截器的主要原因是需要在不修改核心代碼的情況下,靈活地擴展 MyBatis 的功能。常見的應(yīng)用場景包括:

  • 日志記錄:通過攔截器記錄每個 SQL 語句的執(zhí)行情況,包括 SQL 本身、執(zhí)行時間、返回結(jié)果等信息,用于后期分析和調(diào)試。
  • SQL 性能監(jiān)控:攔截器可以用于統(tǒng)計 SQL 執(zhí)行的時間,從而評估 SQL 的性能。長時間執(zhí)行的 SQL 可以被識別出來,作為性能優(yōu)化的目標。
  • 修改 SQL 語句:通過攔截器可以動態(tài)修改 SQL 語句,例如,在查詢中動態(tài)插入條件、修改排序規(guī)則,或者添加分頁邏輯。
  • 事務(wù)控制:在執(zhí)行 SQL 操作之前、之后,或者在某些異常發(fā)生時,攔截器可以用來增強事務(wù)管理。

2. MyBatis 攔截器工作原理

2.1 攔截器的核心概念

MyBatis 攔截器工作時,核心組件是 Invocation、Interceptor、Method 和 Target 對象等:

  • Interceptor:這是所有自定義攔截器的接口,MyBatis 會根據(jù)配置找到并調(diào)用實現(xiàn)該接口的類。
  • Invocation:封裝了方法調(diào)用的對象,它包含了目標方法的信息以及方法的參數(shù)。通過 Invocation 對象,我們可以對方法的執(zhí)行進行控制。
  • Method:表示目標方法,它是通過反射來獲取的。
  • Target:表示目標對象,它是被攔截的對象。例如,Executor、StatementHandler 等都是目標對象,攔截器會通過 Target 對象來訪問和控制這些對象的行為。

2.2 攔截器的生命周期

MyBatis 中,攔截器的生命周期通常包含三個階段:

  1. 插件初始化:當 MyBatis 啟動時,它會加載并初始化所有配置的攔截器。這時,攔截器會準備好攔截邏輯。
  2. 攔截執(zhí)行:當 MyBatis 執(zhí)行某個 SQL 語句時,會觸發(fā)攔截器的 intercept() 方法,這時攔截器會獲取執(zhí)行方法的參數(shù),可以進行修改、增強或替換方法的執(zhí)行。
  3. 插件銷毀:攔截器在 MyBatis 銷毀時會清理資源,釋放占用的內(nèi)存或線程等。

2.3 目標對象和方法

在 MyBatis 中,主要有四個目標對象可以被攔截:

  • Executor:執(zhí)行 SQL 語句的核心對象。它的 update()、query() 等方法負責(zé)執(zhí)行實際的增、刪、改、查操作。
  • StatementHandler:處理 SQL 語句的對象。它負責(zé)將 SQL 語句和參數(shù)綁定,并將其傳遞給數(shù)據(jù)庫。
  • ResultSetHandler:處理 SQL 查詢結(jié)果的對象。它負責(zé)將從數(shù)據(jù)庫返回的 ResultSet 轉(zhuǎn)換為 Java 對象。
  • ParameterHandler:處理 SQL 參數(shù)綁定的對象。它負責(zé)將參數(shù)設(shè)置到 SQL 語句中。

3. MyBatis 攔截器的實現(xiàn)

這里小編會分享工作中實際的案例: 數(shù)據(jù)脫敏。

3.1 自定義脫敏注解

首先需要知曉具體是哪個類中的哪些屬性需要進行脫敏處理,因此,需要自定義注解來實現(xiàn)對需要脫敏的屬性進行標注。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Desensitization {
    StrategyEnum strategy();
}

3.2 脫敏策略

有了標注后,對于脫敏也會涉及到脫敏策略的問題。不同的屬性,應(yīng)該對應(yīng)不同的脫敏方式,例如,名字只保留姓氏,而身份證和電話號碼,則需要對中間的數(shù)字打碼。因此,在使用自定義注解進行標注的同時,也要指定這個屬性對應(yīng)的脫敏策略,這里使用枚舉類枚舉出不同屬性對應(yīng)的正則處理。

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum StrategyEnum {

    NAME(s -> s.replaceAll("([\\u4e00-\\u9fa5]{1})(.*)", "$1*")),
    ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),
    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
    ADDRESS(s -> s.replaceAll("(\\s{8})\\s{4}(\\s*)\\s{4})", "$1****$2****"));

    private final Desensitizer desensitizer;

}

3.3 脫敏執(zhí)行者

對于脫敏處理還需要一個執(zhí)行者,將屬性值和正則表達式進行匹配和替換,進而完成脫敏處理。這里我們利用了JDK8提供的一個非常好用的接口Fuction,它提供了apply方法,這個方法作用是為了實現(xiàn)函數(shù)映射,也就是將一個值轉(zhuǎn)換為另一個值。如果不了解的同學(xué)可以百度下 Fuction 接口。

import java.util.function.Function;

public interface Desensitizer extends Function<String, String> {
}

3.4 自定義數(shù)據(jù)脫敏攔截器

因為要對結(jié)果集進行脫敏處理,所以要攔截的對象肯定是ResultSetHandler,并且是第一個方法。(可以想一下為啥是第一個方法)

public interface ResultSetHandler {
    <E> List<E> handleResultSets(Statement var1) throws SQLException;

    <E> Cursor<E> handleCursorResultSets(Statement var1) throws SQLException;

    void handleOutputParameters(CallableStatement var1) throws SQLException;
}

來看下具體的實現(xiàn):

import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.List;
import java.util.stream.Stream;

@Component
@Intercepts(@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = Statement.class))
public class DesensitizationPlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 獲取結(jié)果集
        List<Object> records = (List<Object>) invocation.proceed();
        // 處理結(jié)果集
        records.forEach(this::desensitization);
        return records;
    }

    /**
     * 2 * 判斷哪些需要脫敏處理
     * 3 * @param source 脫敏之前的源對象
     * 4
     */
    private void desensitization(Object source) {
        // 反射獲取類型中的所有屬性,判斷哪個需要進行脫敏
        Class<?> sourceClass = source.getClass();
        MetaObject metaObject = SystemMetaObject.forObject(source);
        Stream.of(sourceClass.getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(Desensitization.class))
                .forEach(field -> doDesensitization(metaObject, field));
    }

    /**
     * 2 * 真正的脫敏處理
     * 3 * @param metaObject
     * 4
     */
    private void doDesensitization(MetaObject metaObject, Field field) {
        String name = field.getName();
        Object value = metaObject.getValue(name);
        if (value != null && metaObject.getGetterType(name) == String.class) {
            Desensitization annotation = field.getAnnotation(Desensitization.class);
            StrategyEnum strategy = annotation.strategy();
            String apply = strategy.getDesensitizer().apply((String) value);
            metaObject.setValue(name, apply);
        }
    }
}

數(shù)據(jù)脫敏字段:

import com.example.cl.mybatisPlugin.Desensitization;
import com.example.cl.mybatisPlugin.StrategyEnum;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class User {
    private Long id;
    @Desensitization(strategy = StrategyEnum.NAME)
    private String name;
    private Integer age;
}

最后看下脫敏結(jié)果:

圖片圖片

4. 總結(jié)

根據(jù)上面的說明,我們來看看MyBatis 攔截器的優(yōu)勢和不足

  • 優(yōu)勢:

非侵入式:通過攔截器機制,不需要修改 MyBatis 源碼即可定制功能。

靈活性:可以在多個階段對 SQL 操作進行干預(yù),從而實現(xiàn)豐富的功能。

  • 不足:

性能開銷:如果攔截器過多或者邏輯復(fù)雜,可能會導(dǎo)致性能下降。

調(diào)試困難:攔截器的執(zhí)行過程較為隱式,調(diào)試時可能會遇到一定的困難。

因此,我們攔截器不能創(chuàng)建過多,如果攔截的對象同一個,那么我們可以將多個功能放到同一個攔截器當中,從而減少攔截器的創(chuàng)建。

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2025-01-02 10:10:51

2023-11-13 08:16:08

MySQL數(shù)據(jù)數(shù)據(jù)庫

2024-09-09 16:50:21

2019-07-09 08:23:07

數(shù)據(jù)安全旅游網(wǎng)絡(luò)安全

2016-04-29 10:02:39

2024-07-17 08:29:20

2024-08-29 08:58:30

JPA編寫數(shù)據(jù)操

2025-03-11 08:34:22

2016-09-09 01:07:06

數(shù)據(jù)中心容量規(guī)劃數(shù)據(jù)中心

2009-06-24 16:00:00

2009-09-27 17:37:32

Hibernate攔截

2025-02-28 08:14:53

2023-09-05 08:58:07

2019-12-19 08:56:21

MybatisSQL執(zhí)行器

2024-02-28 09:35:52

2011-05-16 10:14:11

Hibernate

2022-03-24 09:13:54

Mybatis加密解密

2011-11-21 14:21:26

SpringMVCJava框架

2025-05-09 08:20:50

2009-07-08 17:02:11

JDK實現(xiàn)調(diào)用攔截器
點贊
收藏

51CTO技術(shù)棧公眾號