偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

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

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

1. 引言

1.1 什么是 MyBatis 攔截器

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

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

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

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

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

1.2 為什么使用攔截器

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

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

2. MyBatis 攔截器工作原理

2.1 攔截器的核心概念

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

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

2.2 攔截器的生命周期

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

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

2.3 目標(biāo)對象和方法

在 MyBatis 中,主要有四個(gè)目標(biāo)對象可以被攔截:

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

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

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

3.1 自定義脫敏注解

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

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 脫敏策略

有了標(biāo)注后,對于脫敏也會(huì)涉及到脫敏策略的問題。不同的屬性,應(yīng)該對應(yīng)不同的脫敏方式,例如,名字只保留姓氏,而身份證和電話號碼,則需要對中間的數(shù)字打碼。因此,在使用自定義注解進(jìn)行標(biāo)注的同時(shí),也要指定這個(gè)屬性對應(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í)行者

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

import java.util.function.Function;

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

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

因?yàn)橐獙Y(jié)果集進(jìn)行脫敏處理,所以要攔截的對象肯定是ResultSetHandler,并且是第一個(gè)方法。(可以想一下為啥是第一個(gè)方法)

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;
}

來看下具體的實(shí)現(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) {
        // 反射獲取類型中的所有屬性,判斷哪個(gè)需要進(jìn)行脫敏
        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)勢:

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

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

  • 不足:

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

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

因此,我們攔截器不能創(chuàng)建過多,如果攔截的對象同一個(gè),那么我們可以將多個(gè)功能放到同一個(gè)攔截器當(dā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

2009-06-24 16:00:00

2016-09-09 01:07:06

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

2009-09-27 17:37:32

Hibernate攔截

2025-02-28 08:14:53

2025-06-09 07:35:00

NumPy數(shù)據(jù)分析數(shù)組

2019-12-19 08:56:21

MybatisSQL執(zhí)行器

2023-09-05 08:58:07

2024-02-28 09:35:52

2011-05-16 10:14:11

Hibernate

2011-11-21 14:21:26

SpringMVCJava框架

2025-05-09 08:20:50

2009-07-08 17:02:11

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

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