精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

MyBatis攔截器在服務內存防護場景中的應用

開發 前端
一個完善的攔截器體系,可顯著提升系統穩定性,有效降低因大數據集查詢導致的故障概率。MyBatis攔截器的價值不在于它處理了多少請求,而在于它阻止了多少災難的發生。

一、內存防護背景:數據庫查詢的潛在風險

二、MyBatis攔截器:基本原理與自定義實現

2.1 核心原理

2.2 自定義攔截器實現步驟

2.3攔截器執行時序

2.4 開發注意事項

三、內存防護方案:基于 MyBatis 攔截器的設計與實踐

3.1 方案整體架構

3.2 Prometheus埋點設計

3.3 攔截器執行全流程

3.4 攔截器基礎版關鍵代碼

3.5 查詢結果大小統計

3.6 擴展功能

四、價值與收益:內存防護方案的核心價值與效果收益

4.1 核心價值

4.2 效果收益

五、總結

一、內存防護背景:數據庫查詢的潛在風險

Java服務中,數據庫查詢返回過大數據集可能引發兩類風險:

  1. 結果集字節過大(如單結果集超過20MB)
  • 直接導致JVM堆內存飆升
  • 頻繁觸發Full GC甚至OOM崩潰
  1. 結果集行數過多(如單次查詢返回10萬行)
  • 應用層對象轉換消耗大量CPU
  • 線程阻塞導致接口超時

為規避數據庫查詢返回過大數據集引發的內存風險,需在數據訪問對象(DAO)層構建精準的監控與攔截機制,實現對查詢結果集規模的有效把控。

MyBatis作為主流ORM框架,能夠高效地將數據庫操作轉化為Java對象操作。其攔截器功能可為內存防護提供理想的解決方案,核心優勢包括:

  • 無侵入式改造:無需修改原有業務邏輯,通過攔截SQL執行流程嵌入自定義邏輯
  • 精準攔截時機:基于MyBatis執行生命周期,可在查詢執行前/后靈活融入監控與控制邏輯

這種無侵入式的開發方式,最大程度保障了原有系統的穩定性與可維護性,為系統安全穩定運行保駕護航。

二、MyBatis攔截器:基本原理與自定義實現

2.1 核心原理

MyBatis攔截器采用動態代理模式,在SQL執行關鍵節點插入自定義邏輯(比如修改 SQL、處理參數、包裝結果等), 在不破壞原有代碼結構的前提下,對 MyBatis 的核心流程進行改造。

核心原理:4大對象 + 攔截器鏈

四大核心對象

MyBatis的SQL執行流程依賴四大核心對象:

  • Executor:管理SQL執行的全過程(如 query、update、commit、rollback)。
  • StatementHandler:可以在SQL語句執行之前修改或增強它們。
  • ParameterHandler:可以在將參數設置到SQL語句之前修改或驗證它們。
  • ResultSetHandler:可以在將結果集返回給應用程序之前修改或分析它們。

四大核心對象四大核心對象

攔截器鏈工作機制

攔截器通過攔截四大核心對象的特定方法,形成一條“攔截器鏈”。當SQL執行到對應節點時,會依次觸發鏈中攔截器的邏輯,就像工廠流水線中增加了自定義質檢環節。

攔截器鏈工作流程攔截器鏈工作流程

2.2 自定義攔截器實現步驟

一個攔截器從定義到生效,需要經歷三個關鍵階段:

  1. 定義階段:通過@Intercepts和@Signature注解聲明攔截目標
  2. 注冊階段:在MyBatis配置文件中配置攔截器
  3. 執行階段:當目標方法被調用時,攔截器鏈按順序執行攔截邏輯

自定義攔截器流程自定義攔截器流程

1. @Intercepts注解聲明攔截目標

@Intercepts({
    @Signature(type = ResultSetHandler.class,
               method = "handleResultSets",
               args = {Statement.class})
})
  • type:攔截的四大接口之一(Executor、StatementHandler等)
  • method:目標方法名
  • args:方法參數類型

2. 實現Interceptor接口

public class GuardInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 前置處理
        preProcess(invocation);
        
        // 執行原方法
        Object result = invocation.proceed();
        
        // 后置處理
        postProcess(invocation, result);
        return result;
    }
}

3. 注冊攔截器

在MyBatis配置文件中增加:

<plugins>
  <plugin interceptor="com.example.GuardInterceptor">
    <property name="maxBytes" value="20971520"/>
  </plugin>
</plugins>

2.3攔截器執行時序

攔截器執行時序攔截器執行時序

2.4 開發注意事項

性能相關

  • 避免在攔截器中做復雜計算
  • 結果集分析可采用異步模式

一致性相關

  • 攔截器中避免開啟新事務
  • 寫操作攔截需嚴格測試

三、內存防護方案:基于 MyBatis 攔截器的設計與實踐

3.1 方案整體架構

方案整體架構圖方案整體架構圖


3.2 Prometheus埋點設計

metric類型為Histogram類型,Histogram的duration存儲SQL查詢的耗時,包含三個label:Mapper方法、行數等級、字節數等級。Prometheus指標

  • Mapper方法:SQL對應的Mapper方法
  • 行數等級:結合業務實際場景,將SQL查詢結果的行數劃分為5級(L0~L5)。
  • 字節數等級:結合業務實際場景,將SQL查詢結果的字節大小劃分為6級(L0~L6)

不同等級對應不同的風險程度,有助于監控查詢結果的數據量對系統的影響。

  1. 行數等級:
  • 聚焦數據量維度
  • 有效預防全表掃描
  • 核心指標:L3為性能拐點,L4+需強制限制
  1. 字節數等級:
  • 聚焦單行數據大小
  • 識別大對象問題
  • 關鍵閾值:L3(1MB)為內存警戒線

行數等級劃分

行數等級劃分

字節數等級劃分

字節數等級劃分字節數等級劃分

指標定義

public class SqlExecutionMetrics {
    // 統一Histogram指標
    staticfinal Histogram SQL_QUERY_STATS = Histogram.build()
        .name("sql_query_stats")
        .help("SQL執行綜合統計")
        .labelNames("dao_method", "row_level", "byte_level")
        .buckets(10, 50, 100, 500, 1000, 5000) // 耗時桶
        .register();
    
    // 行數等級映射規則
    privatestaticfinalint[] ROW_LEVELS = {0, 100, 1000, 10000, 50000};
    
    // 字節等級映射規則 (單位: KB)
    privatestaticfinalint[] BYTE_LEVELS = {0, 100, 1024, 10240, 102400, 1024000};
}

3.3 攔截器執行全流程

攔截器執行全流程攔截器執行全流程

主要通過攔截Executor的query方法,在SQL執行前后嵌入相關邏輯。

3.4 攔截器基礎版關鍵代碼

@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})

})
public class EnhancedMemoryGuardInterceptor implements Interceptor {
   // 雙閾值配置  
   privateint rowWarnThreshold = 3000;
   privateint rowBlockThreshold = 10000;
   privatelong byteWarnThreshold = 5 * 1024 * 1024; // 5MB  
   privatelong byteBlockThreshold = 10 * 1024 * 1024; // 10MB  

   @Override
   public Object intercept(Invocation invocation) throws Throwable {
      long startTime = System.currentTimeMillis();
      // 執行原始SQL
      Object result = invocation.proceed();
      long endTime = System.currentTimeMillis();
      try {
         long duration = endTime - startTime;
         String sqlId = getSqlId(invocation);
         // 結果集行數
         int rowCount;
         if (result instanceof Collection) {
            rowCount = ((Collection<?>) result).size();
         } else {
            rowCount = result == null ? 0 : 1;
         }

         // 結果字節數
         long byteSize = MemoryMeasurer.measureBytes(result);

         // 等級映射
         int rowLevel = mapToLevel(rowCount, SqlExecutionMetrics.ROW_LEVELS);
         int byteLevel = mapToLevel(byteSize / 1024, SqlExecutionMetrics.BYTE_LEVELS);

         // Prometheus埋點
         recordMetrics(sqlId, rowLevel, byteLevel, duration);

         // 雙閾值檢測
         checkRowThresholds(sqlId, rowCount, duration);
         checkByteThresholds(sqlId, byteSize, duration);
      } catch (MemoryGuardException e) {
         throw e;
      } catch (Exception e) {
         log.error("EnhancedMemoryGuardInterceptor unknow error", e);
      }

      return result;
   }

   // 等級映射算法  
   private int mapToLevel(long value, int[] thresholds) {
      for (int i = 0; i < thresholds.length; i++) {
         if (value <= thresholds[i]) {
            return i;
         }
      }

      return thresholds.length;
   }

   // 行數閾值檢測  
   private void checkRowThresholds(String sqlId, int rowCount, long duration) {
      if (rowCount > rowWarnThreshold) {
         String warnMsg = String.format(
                 "[行數告警] SQL:%s 返回%d行(閾值:%d) 耗時:%dms",
                 sqlId, rowCount, rowWarnThreshold, duration
         );
         // 發送企微告警
         WeComAlarm.send(warnMsg);

         if (rowCount >= rowBlockThreshold) {
            thrownew MemoryGuardException(warnMsg + "\n[已熔斷] 超過阻斷閾值:" + rowBlockThreshold);
         }
      }
   }

   // 字節閾值檢測  
   private void checkByteThresholds(String sqlId, long byteSize, long duration) {
      if (byteSize > byteWarnThreshold) {
         String warnMsg = String.format(
                 "[字節告警] SQL:%s 占用%.2fMB(閾值:%dMB) 耗時:%dms",
                 sqlId, byteSize / (1024.0 * 1024.0),
                 byteWarnThreshold / (1024 * 1024), duration
         );
         // 發送企微告警
         WeComAlarm.send(warnMsg);

         if (byteSize >= byteBlockThreshold) {
            thrownew MemoryGuardException(warnMsg + "\n[已熔斷] 超過阻斷閾值:" +
                    byteBlockThreshold / (1024 * 1024) + "MB");
         }
      }
   }

   // 記錄Prometheus指標  
   private void recordMetrics(String sqlId, int rowLevel, int byteLevel, long duration) {
      SqlExecutionMetrics.SQL_QUERY_STATS.labels(sqlId, String.valueOf(rowLevel), String.valueOf(byteLevel))
                                         .observe(duration);
   }
}

3.5 查詢結果大小統計

計算對象大小的方案:

  • 輕量級估算字節大?。ɑ陬愋痛笮∮成?,累加對象每個字段的字節大小)
  • 序列化后獲取字節大?。ㄊ褂肂yteArrayOutputStream)
  • JSON序列化獲取字節大?。ɡ缡褂肑ackson)

不同方案對比

特性

輕量級估算

ByteArrayOutputStream

JSON序列化

實現原理

基于類型映射的快速計算

Java對象序列化為字節流

對象轉為JSON字符串

計算方式

字段遍歷+類型映射

完整對象序列化

對象轉為JSON文本

性能

極高 (納秒級)

低 (微秒級)

中 (微秒級)

精度

中等 (估算值)

高 (精確序列化大小)

高 (文本字節大小)

內存消耗

極低

中高

適用對象

簡單POJO/Map

Serializable對象

所有對象

特殊類型

需特殊處理

自動處理

需自定義序列化

是否改變對象

額外依賴

JSON庫(Jackson等)

在MyBatis攔截器這種性能敏感的場景中,輕量級估算方案明顯優于序列化方法,它能以極小的性能開銷提供足夠準確的大小估算,滿足監控和日志記錄的需求。

輕量級估算實現

public abstractclass MemoryMeasurer {

    /**
     * 對象大小計算器接口
     */
    @FunctionalInterface
    publicinterface SizeCalculator {
        long calculate(Object obj);
    }

    // 類型估算器注冊表
    privatestaticfinal Map<Class<?>, SizeCalculator> SIZE_CALCULATORS = new ConcurrentHashMap<>();

    static {
        // 注冊基本類型估算器
        SIZE_CALCULATORS.put(Byte.class, obj -> 1);
        SIZE_CALCULATORS.put(Short.class, obj -> 2);
        SIZE_CALCULATORS.put(Integer.class, obj -> 4);
        SIZE_CALCULATORS.put(Long.class, obj -> 8);
        SIZE_CALCULATORS.put(Float.class, obj -> 4);
        SIZE_CALCULATORS.put(Double.class, obj -> 8);
        SIZE_CALCULATORS.put(Boolean.class, obj -> 1);
        SIZE_CALCULATORS.put(Character.class, obj -> 2);

        // 注冊常用對象類型估算器
        SIZE_CALCULATORS.put(String.class, obj ->
                ((String) obj).getBytes(StandardCharsets.UTF_8).length);

        SIZE_CALCULATORS.put(BigDecimal.class, obj ->
                obj.toString().getBytes(StandardCharsets.UTF_8).length);

        // 注冊日期時間類型估算器
        SIZE_CALCULATORS.put(Date.class, obj -> 8);
        SIZE_CALCULATORS.put(java.sql.Date.class, obj -> 8);
        SIZE_CALCULATORS.put(java.sql.Time.class, obj -> 8);
        SIZE_CALCULATORS.put(java.sql.Timestamp.class, obj -> 8);
        SIZE_CALCULATORS.put(LocalDate.class, obj -> 6);
        SIZE_CALCULATORS.put(LocalTime.class, obj -> 5);
        SIZE_CALCULATORS.put(LocalDateTime.class, obj -> 12);
        SIZE_CALCULATORS.put(Instant.class, obj -> 12);
        SIZE_CALCULATORS.put(ZonedDateTime.class, obj -> 20);
        SIZE_CALCULATORS.put(OffsetDateTime.class, obj -> 16);

        // 注冊字節數組類型
        SIZE_CALCULATORS.put(byte[].class, obj -> ((byte[]) obj).length);
    }

    /**
     * 估算結果集大小
     */
    public static long measureBytes(Object result) {
        if (result == null) {
            return0;
        }

        if (result instanceof List) {
            List<?> list = (List<?>) result;
            if (list.isEmpty()) {
                return0;
            }

            // 遍歷所有行進行估算
            long totalSize = 0;
            for (Object row : list) {
                totalSize += estimateRowSize(row);
            }
            return totalSize;
        }

        // 單個對象結果
        return estimateRowSize(result);
    }

    /**
     * 估算單行大小
     */
    private static long estimateRowSize(Object row) {
        if (row == null)
            return0;

        long rowSize = 0;

        if (row instanceof Map) {
            // Map類型結果(如selectMap)
            Map<?, ?> rowMap = (Map<?, ?>) row;
            for (Object value : rowMap.values()) {
                rowSize += estimateValueSize(value);
            }
        } else {
            // 實體對象類型
            List<Field> cachedFields = getCachedFields(row.getClass());
            for (Field field : cachedFields) {
                try {
                    field.setAccessible(true);
                    Object value = field.get(row);
                    rowSize += estimateValueSize(value);
                } catch (IllegalAccessException e) {
                    // 忽略無法訪問的字段
                }
            }
        }

        // 加上對象頭開銷(約16字節)
        return rowSize + 16;
    }

    /**
     * 估算單個值的大小
     */
    private static long estimateValueSize(Object value) {
        if (value == null) {
            return0;
        }

        Class<?> valueClass = value.getClass();
        // 查找精確匹配的估算器
        SizeCalculator calculator = SIZE_CALCULATORS.get(valueClass);
        if (calculator != null) {
            return calculator.calculate(value);
        }

        // 嘗試父類或接口匹配
        for (Map.Entry<Class<?>, SizeCalculator> entry : SIZE_CALCULATORS.entrySet()) {
            if (entry.getKey().isAssignableFrom(valueClass)) {
                return entry.getValue().calculate(value);
            }
        }

        // 默認處理:使用toString的字節長度
        return value.toString().getBytes(StandardCharsets.UTF_8).length;
    }

    // 緩存字段反射結果
    privatestaticfinal Map<Class<?>, List<Field>> FIELD_CACHE = new ConcurrentHashMap<>();

    /**
     * 獲取類的字段映射(包括父類)
     */
    private static List<Field> getCachedFields(Class<?> clazz) {
        return FIELD_CACHE.computeIfAbsent(clazz, k -> {
            List<Field> fields = new ArrayList<>();
            Class<?> current = clazz;
            while (current != Object.class) {
                Collections.addAll(fields, current.getDeclaredFields());
                current = current.getSuperclass();
            }

            return fields;
        });
    }
}

針對各種Java類型提供專門的估算邏輯:

數據類型

估算大小 (字節)

說明

基本類型

固定大小

byte(1), short(2), int(4), long(8)等

字符串

UTF-8字節長度

使用str.getBytes(StandardCharsets.UTF_8).length

BigDecimal/BigInteger

字符串表示長度

使用toString().getBytes().length

日期時間

固定大小

LocalDate(6), LocalTime(5), LocalDateTime(12)等

其他對象

toString()長度

默認處理方式

3.6 擴展功能

異步監控機制

僅監控,不使用熔斷功能場景:線程池異步處理大小估算、行數統計及等級判定,避免阻塞主線程。

配置化管理

配置中心或自定義注解或Spring配置支持

  • 告警閾值配置(表級別)
  • 熔斷閾值配置(表級別)
  • 是否打印詳細日志
  • 采樣比例
  • 白名單/黑名單判斷

深度統計分析

對象的字節數統計信息支持到字段級別,包括:每個字段的總大小、平均大小、最大值、最小值。

通過字段級別的大小分布,可識別以下問題:哪些字段占用空間最多、是否存在異常大字段、數據分布是否均勻。

動態閾值調整

根據歷史數據自動調整等級閾值或熔斷閾值

public void adjustLevelThresholds() {
    // 獲取最近7天行數P95值
    double p95Rows = queryThresholdP95FromPrometheus();
    
    // 調整行數等級閾值
    ROW_LEVELS[3] = (int)(p95Rows * 0.8);  // 降低20%
    ROW_LEVELS[4] = (int)(p95Rows * 1.2);  // 提高20%
    
    // 調整字節等級閾值...
}

高風險查詢識別

支持識別高風險查詢組合

  • 應用服務增加多維度告警
// 行數+字節雙維度熔斷策略
for (LevelConfig config : levelConfigs) {
   if (byteLevel >= config.byteLevel && rowLevel >= config.rowLevel) {
       blockAndAlert("高危組合: 行數" + rowCount + " 字節" + byteSize + "MB");
   }
}
  • Prometheus告警中心自定義告警
# L3+行數等級且L3+字節數等級的查詢
sum by (dao_method) (
rate(sql_query_stats{row_level=~"[3-5]", byte_level=~"[3-5]"}[5m])
        ) > 10

慢查詢告警

根據SQL執行耗時做定制化的有更多上下文的慢查詢告警

四、價值與收益:內存防護方案的核心價值與效果收益

4.1 核心價值

1. 多維度監控

  • 方法粒度:精確到每個Mapper方法
  • 行數維度:識別數據量風險(如全表掃描、大范圍in查詢)
  • 字節數維度:發現大對象問題(如超長文本字段、大JSON字段)

2. 安全預警

  • 基于等級變化趨勢提前預警(如L3級行數占比突增30%)
  • 觸發熔斷閾值時主動阻斷高危查詢

3. 根因定位

通過Prometheus標簽組合快速定位問題SQL

4. 容量規劃

基于歷史等級分布數據預測內存/CPU資源需求

4.2 效果收益

1. 系統穩定性提升

通過對數據庫查詢結果集大小的精細化管控(如限制行數、字節數),直接遏制了因大數據集返回導致的內存異常風險。

  • 避免JVM堆內存突發飆升引發的Full GC頻繁觸發、服務響應延遲等連鎖問題
  • 降低系統因內存溢出(OOM)導致的非計劃停機概率,使服務運行狀態更平穩

2. 資源利用優化

減少不必要的大數據集加載對CPU、內存等硬件資源的過度消耗:

  • 避免個別查詢占用過多資源而擠壓其他業務請求的資源空間
  • 讓系統資源更合理地分配到核心業務邏輯處理中,提升整體資源利用率和服務承載能力

3. 問題排查效率提高

攔截器收集的行數、字節數、執行耗時等多維度指標,為開發人員提供了精準的排查依據:

  • 可快速定位存在性能隱患的SQL查詢 -- 通過“行數等級”“字節數等級”等標簽,直觀識別高風險查詢操作(如全表掃描、大對象查詢)
  • 為SQL優化、表結構調整等工作提供明確方向,縮短問題診斷周期

4. 業務連續性保障

熔斷機制與告警機制協同作用,保障核心業務流程正常運轉:

  • 熔斷機制:在查詢結果超過阻斷閾值時主動阻斷危險查詢,防止其對系統造成更大范圍影響
  • 告警機制:及時將潛在風險(如接近閾值的查詢)通知相關人員,使其有充足時間介入處理,將問題解決在萌芽狀態,減少了因系統故障對業務造成的損失

5. 開發規范強化

攔截器形成隱性約束,推動團隊開發習慣優化:

  • 促使開發人員在編寫SQL時更注重結果集大小控制,培養“按需查詢”的良好習慣
  • 間接推動SQL優化、分頁查詢等規范落地,從源頭減少高風險查詢的產生

五、總結

MyBatis攔截器可以以極低成本防止服務因失控查詢崩潰,在內存防護中充當“安全閘門”,在關鍵時刻:

  • 感知危險操作
  • 攔截潛在風險
  • 傳遞關鍵信息

一個完善的攔截器體系,可顯著提升系統穩定性,有效降低因大數據集查詢導致的故障概率。MyBatis攔截器的價值不在于它處理了多少請求,而在于它阻止了多少災難的發生。

技術不會讓系統永不故障,但好的防御體系能讓故障成為可控事件。在追求系統穩定性的道路上,MyBatis攔截器是每位工程師值得信賴的伙伴。

關于作者:申定文 轉轉Java開發工程師

責任編輯:武曉燕 來源: 轉轉技術
相關推薦

2025-07-15 02:00:00

2025-05-09 08:20:50

2025-08-01 07:07:18

2024-12-27 08:39:10

2025-01-02 10:10:51

2023-09-05 08:58:07

2024-02-28 09:35:52

2009-06-24 16:00:00

2013-11-04 09:35:38

Firefox插件攔截FLASH

2009-09-27 17:37:32

Hibernate攔截

2025-02-28 08:14:53

2024-05-06 00:00:00

C#工具代碼

2020-03-25 17:55:30

SpringBoot攔截器Java

2019-12-19 08:56:21

MybatisSQL執行器

2011-05-16 10:14:11

Hibernate

2009-07-08 17:02:11

JDK實現調用攔截器

2011-11-21 14:21:26

SpringMVCJava框架

2024-12-04 08:50:03

2024-05-13 09:32:06

攔截器HTTP中間件

2009-06-25 15:54:42

Struts2教程攔截器
點贊
收藏

51CTO技術棧公眾號

久久久亚洲欧洲日产国码aⅴ| 欧美性猛交xxxxxxxx| 国产日韩欧美精品| 日韩av免费播放| 伊人久久大香线蕉精品组织观看| 欧美精品一区二区三区视频| 亚洲精品一二三四五区| 欧美野外wwwxxx| 久久久精品2019中文字幕之3| 成人黄色片网站| 成年人免费高清视频| 五月久久久综合一区二区小说| 欧美精品一区二区三区在线播放 | 欧美sm极限捆绑bd| 亚洲综合欧美激情| 不卡av播放| 亚洲午夜免费电影| 在线无限看免费粉色视频| 欧美美女搞黄| 国产成人在线视频网站| 国产精品久久久久9999| 日韩精品在线不卡| 欧美三级特黄| 日韩在线观看免费高清| 动漫美女无遮挡免费| 99精品视频在线免费播放 | 精品久久久久久久免费人妻| 日本孕妇大胆孕交无码| 国产精品美女久久久久久久久| 国产自产精品| 亚洲精品国产精| 国产自产2019最新不卡| 国产欧美一区二区白浆黑人| 无码无套少妇毛多18pxxxx| 亚洲欧洲午夜| 欧美精品video| 欧美成人免费看| 国产精品97| 中文字幕精品在线视频| 亚洲码无人客一区二区三区| 日韩高清电影免费| 亚洲国产天堂久久综合网| 99sesese| 四虎视频在线精品免费网址| 欧美优质美女网站| 三级在线视频观看| 一二区成人影院电影网| 色婷婷狠狠综合| 欧美成人精品欧美一级乱| 国产精品蜜芽在线观看| 五月天中文字幕一区二区| 免费看污久久久| 隣の若妻さん波多野结衣| 国产成人一区在线| 成人欧美一区二区| 蜜臀久久99精品久久久| 成人国产亚洲欧美成人综合网 | 日本午夜精品理论片a级appf发布| 亚洲黄色一区二区| 久久不射2019中文字幕| 国产va免费精品高清在线观看| 国产午夜麻豆影院在线观看| 久久中文在线| 国产精品久久一区主播| 一级黄色免费片| 国产在线不卡视频| 国产精品国产亚洲精品看不卡15 | 九九热这里只有在线精品视| 久久99久久99精品蜜柚传媒| 日韩在线观看视频一区| 国产精品迅雷| 色婷婷精品大在线视频| 亚洲精品视频导航| 成人在线啊v| 日韩欧美你懂的| www.日韩av.com| 91人妻一区二区三区蜜臀| 一个色综合网| 性金发美女69hd大尺寸| 波多野结衣绝顶大高潮| 国内精品伊人久久久久av影院 | 久久精品福利视频| 福利一区二区三区四区| 日韩精品乱码av一区二区| 91免费看片网站| 天天操天天干天天爱| 国产精品天天摸av网| 日韩成人午夜影院| 国产精品专区免费| 欧美一级片在线| 巨胸大乳www视频免费观看| 久久精品国产68国产精品亚洲| 欧美黄色www| 国产在线一级片| 国产馆精品极品| 奇米视频888战线精品播放| 毛片在线不卡| 欧美色播在线播放| 51自拍视频在线观看| 亚洲桃色综合影院| 九九九久久久久久| 波多野结衣午夜| 成人视屏免费看| 一区二区精品在线观看| 成人观看网址| 欧美一级片在线看| 性猛交娇小69hd| 亚洲承认在线| 91免费的视频在线播放| 亚洲av毛片成人精品| 亚洲精品国产品国语在线app| 久久综合久久色| 麻豆成人入口| 欧美激情xxxx| 91中文字幕在线播放| 久久久久亚洲蜜桃| 和岳每晚弄的高潮嗷嗷叫视频| 日本免费一区二区三区等视频| 亚洲精品视频二区| 亚洲视频免费播放| 成人美女在线视频| 成人国产一区二区三区| 久久91导航| 日韩成人中文电影| 日本天堂网在线观看| 国产精品亚洲а∨天堂免在线| 亚洲一区二区三区涩| 日韩性xxx| 亚洲精品一区中文| 久久草视频在线| av午夜精品一区二区三区| 伊人久久在线观看| 欧美国产中文高清| 欧美成人激情视频| 国产毛片一区二区三区va在线| 亚洲国产精品成人综合色在线婷婷 | 欧美情侣在线播放| 欧美色图17p| 麻豆精品久久久| 亚洲巨乳在线观看| 激情久久一区二区| 自拍视频国产精品| 亚洲一区二区三区高清视频| 国产精品嫩草99a| 牛夜精品久久久久久久| 久久高清免费| 96pao国产成视频永久免费| 嫩草在线视频| 91.com视频| 青青草免费av| 懂色av一区二区三区蜜臀| 国产视频在线观看网站| 精品精品国产三级a∨在线| 97精品伊人久久久大香线蕉| 偷拍自拍在线| 在线观看一区二区视频| av资源在线免费观看| 国产在线精品国自产拍免费| 妞干网视频在线观看| а√中文在线天堂精品| 韩国视频理论视频久久| 天堂在线中文| 欧美视频一区二| 神马午夜精品91| 大美女一区二区三区| 成人av一级片| jlzzjlzz亚洲女人| 91精品久久久久久久久中文字幕 | 国产精品九九久久久久久久| 视频免费一区| 精品欧美久久久| 亚洲日本视频在线观看| 国产欧美视频一区二区三区| 亚洲一区精品视频在线观看| 红桃视频国产精品| 欧美日韩在线精品| 天堂综合在线播放| 国内精品中文字幕| 成年人在线视频| 日韩写真欧美这视频| 免费看日韩毛片| 国产精品女同互慰在线看| 麻豆tv在线观看| 美日韩精品视频| 裸体裸乳免费看| 亚洲老女人视频免费| 成人免费午夜电影| 国内精彩免费自拍视频在线观看网址| 国产一区二区三区四区福利| 精品人妻一区二区三区浪潮在线| 天天色综合成人网| 青青操在线视频观看| 波多野结衣在线一区| 伊人网在线综合| 99热在线精品观看| 91免费视频黄| 国产成人黄色| 国产chinese精品一区二区| 女海盗2成人h版中文字幕| 日韩亚洲综合在线| 国产系列在线观看| 亚洲成人中文字幕| 99产精品成人啪免费网站| 日韩欧美亚洲国产一区| 欧美成欧美va| 中文字幕在线一区二区三区| 国产 中文 字幕 日韩 在线| 国产一区二区三区在线观看精品 | 欧美片第一页| 久久久久久亚洲精品不卡| 色多多视频在线观看| 日韩理论片久久| 可以免费观看的毛片| 在线播放中文字幕一区| 亚洲中文字幕无码爆乳av| 亚洲成人黄色影院| 国产女人被狂躁到高潮小说| 亚洲国产精品成人综合| 大又大又粗又硬又爽少妇毛片 | 国产一区二区三区四区在线| av电影在线观看完整版一区二区| 6080国产精品| 久久精品99国产精品日本| 国产精品视频分类| 丝袜美腿亚洲一区二区图片| 国产av国片精品| 国内一区二区三区| av 日韩 人妻 黑人 综合 无码| 99久久婷婷国产综合精品电影√| 日韩啊v在线| 国内精品久久久久久久影视简单| 久久涩涩网站| 亚洲丁香日韩| 久久久久网址| 日韩动漫一区| 你懂的网址一区二区三区| 林ゆな中文字幕一区二区| 国产一区二区免费在线观看| 国产suv精品一区| 国产精品初高中精品久久| 日韩中文一区二区| 动漫一区二区在线| 国产精品视屏| 激情一区二区三区| 亚洲免费观看高清完整版在线观| 久久av免费一区| 色橹橹欧美在线观看视频高清 | 亚洲字幕久久| 波多野结衣 作品| 欧美久久视频| 国产精品12345| 先锋a资源在线看亚洲| 欧美 日韩精品| 视频一区在线视频| 激情黄色小视频| 国产乱码精品一区二区三| 亚洲av无一区二区三区久久| 成人国产精品免费观看| 7788色淫网站小说| 国产午夜亚洲精品羞羞网站| 久久午夜精品视频| 亚洲人成精品久久久久| 久久久久免费看| 日韩欧美在线视频日韩欧美在线视频 | 国产精品久久国产精品| 日本欧美韩国国产| 日韩免费一区二区三区| 久久久久国产精品| 日韩黄色片在线| 午夜在线精品| 五月天丁香花婷婷| jlzzjlzz国产精品久久| 久久av无码精品人妻系列试探| 一色桃子久久精品亚洲| 日韩精品一区三区| 欧美性感一区二区三区| 国产xxxx孕妇| 亚洲男子天堂网| 国产在线观看a| 7777免费精品视频| 国产精品久久久久77777丨| 99久久国产免费免费| 亚洲精品一级二级三级| 亚洲黄色网址在线观看| 亚洲一区二区三区免费在线观看 | 久久久精品黄色| 免费在线黄色网| 色综合久久99| av小说天堂网| 国产亚洲精品久久久久久| av网址在线看| 日韩女优在线播放| 日韩精品一区二区三区免费视频| 欧美不卡在线一区二区三区| 91精品一区国产高清在线gif| 久久久久久久久久久视频| 国产美女主播视频一区| 加勒比一区二区| 亚洲国产日产av| 一卡二卡三卡在线| 日韩h在线观看| 91亚洲天堂| 国产精品视频精品| 亚瑟一区二区三区四区| 丁香色欲久久久久久综合网| 蜜臀av性久久久久av蜜臀妖精 | 毛葺葺老太做受视频| 成人一级视频在线观看| 中文字幕无码日韩专区免费| 色视频欧美一区二区三区| 亚洲男人天堂久久| 欧美xxxx做受欧美.88| 国产一区二区三区四区五区3d| 精品中文字幕人| 激情综合网址| wwwxxxx在线观看| 亚洲少妇中出一区| 探花国产精品一区二区| 日韩经典中文字幕| 精品极品在线| 国产伦精品一区二区三区视频免费 | 性插视频在线观看| 欧美俄罗斯性视频| 视频精品国内| 2021国产视频| 国产一区二区按摩在线观看| www.99re6| 欧美日韩在线播放三区四区| 高清美女视频一区| 欧美在线视频一区| 欧美五码在线| 免费无码不卡视频在线观看| 成人h版在线观看| 国产在线精品观看| 亚洲精品一区二区三区精华液| 美女精品导航| 国产伦精品一区二区| 激情久久久久| 无码人妻精品一区二区三| 亚洲一二三四区不卡| 狠狠综合久久av一区二区| 性色av一区二区三区| 欧美顶级毛片在线播放| 日韩小视频在线播放| 久久在线观看免费| 久久精品无码av| 在线播放日韩精品| 亚洲综合资源| 久久久久久久久影视| 成人午夜电影网站| 久久人妻免费视频| 国产亚洲欧美一区| 亚洲欧美一级| 欧美视频在线第一页| av在线综合网| 亚洲欧美偷拍视频| 中文字幕视频在线免费欧美日韩综合在线看 | 国产一区观看| 国产精品无码毛片| 在线观看精品一区| 黄网站免费在线播放| 99免费在线视频观看| 日韩午夜免费视频| 欧美成人国产精品一区二区| 欧美日韩一二三| 污污网站在线观看| 久久久福利视频| 日韩激情视频在线观看| 小早川怜子一区二区的演员表| 欧美videos大乳护士334| 韩国久久久久久| 中文字幕一区二区三区在线乱码| 国产成人免费视| 国产美女激情视频| 日韩在线观看免费网站| 国产精品白丝av嫩草影院| 女人另类性混交zo| 亚洲色大成网站www久久九九| 四虎永久在线精品免费网址| 国产高清在线不卡| 国产综合精品| 欧美大波大乳巨大乳| 欧美一区二区免费| 欧美一级大黄| 欧美一区二区三区综合| 久久久久久麻豆| 国产乱淫av免费| 欧美与黑人午夜性猛交久久久| 99九九热只有国产精品| 精品中文字幕在线播放| 欧美精品粉嫩高潮一区二区| 91禁在线看| 亚洲日本精品一区| 94色蜜桃网一区二区三区| 97在线公开视频| 日韩美女视频免费看| 激情欧美丁香| 999精品视频在线观看播放| 亚洲精品资源美女情侣酒店| 精品国产不卡一区二区|