精品欧美一区二区三区在线观看 _久久久久国色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级在线观看| 欧日韩在线视频| 奇米在线7777在线精品| 欧美成人精品影院| 91精品人妻一区二区三区蜜桃欧美| 亚洲精品第一| 欧美性高潮在线| 亚洲黄色一区二区三区| 欧美一区二区黄片| 精品一区二区三区在线观看 | 国产精品一国产精品k频道56| 伊人成人开心激情综合网| 无码人妻aⅴ一区二区三区玉蒲团| 亚洲伦理影院| 午夜一区二区三区在线观看| 亚洲一区二区在线看| 欧美色图另类| 成人晚上爱看视频| 91色p视频在线| 中文字幕 欧美激情| 一本不卡影院| 欧美精品久久久久久久久久| 亚洲欧美卡通动漫| 国产精品嫩草影院在线看| 精品国产91亚洲一区二区三区婷婷 | 欧美天堂一区二区三区| 国产超级av在线| 污视频免费在线观看| 中文字幕一区视频| 亚洲v日韩v欧美v综合| 日韩私人影院| 久久综合久久久久88| 国产精品久久7| 精品人妻久久久久一区二区三区| 美女免费视频一区| 国产精品视频最多的网站| 国产精品自拍99| 99亚洲一区二区| 97精品视频在线观看| 日韩av电影网址| 亚洲黄页一区| 91精品国产免费久久久久久| 日本熟妇色xxxxx日本免费看| 欧美激情性爽国产精品17p| 久久久精品免费| 国产一二三区精品| 中文精品电影| 欧美大秀在线观看| 日韩成人av毛片| 宅男噜噜噜66国产日韩在线观看| 性色av一区二区三区| 国产精品国产三级国产专区52 | 国产精品入口免费软件| 精品视频一区二区三区四区五区| 日本福利一区二区| 成人黄色一区二区| 国产精品成人国产| 666欧美在线视频| 日本少妇一区二区三区| av成人资源网| 日韩精品在线看| 亚洲天堂最新地址| 91九色精品| 欧美黑人巨大xxx极品| 日韩精品手机在线| 国产精品色网| 国产精品美女午夜av| 97精品人妻一区二区三区香蕉| 国产在线不卡一区| 国产91社区| 亚洲日本在线播放| 国产精品久久久久影院色老大| 超碰成人在线免费观看| av中文在线资源| 91九色02白丝porn| 国产男女无遮挡猛进猛出| 国产亚洲精品美女久久| 亚洲欧洲免费视频| 四虎永久免费在线| 国产麻豆综合| 91亚洲精品久久久| 五月婷婷在线观看视频| 国产精品久久免费看| 台湾无码一区二区| 天天免费亚洲黑人免费| 日韩一级片在线观看| 人妻体内射精一区二区| 久久久久久久久国产一区| 69av成年福利视频| 国产精品无码白浆高潮| 91丨九色porny丨蝌蚪| 国产高清免费在线| 神马久久资源| 亚洲国产精品一区二区三区| 青青青视频在线免费观看| 日韩午夜激情| 亚洲自拍偷拍色片视频| 精彩国产在线| 亚洲成a人片在线不卡一二三区| 成人性生生活性生交12| 98视频精品全部国产| 中文字幕日韩电影| 国产一级做a爱片久久毛片a| 狠狠网亚洲精品| 欧美日韩视频在线一区二区观看视频| 深夜国产在线播放| 欧美日韩国产综合视频在线观看| 蜜桃精品成人影片| 国内精品福利| 91精品视频播放| 北条麻妃在线| 色综合天天性综合| 日韩av手机在线播放| 欧美一区二区三区久久精品茉莉花 | 日日噜噜噜夜夜爽爽| 精品国模一区二区三区| 亚洲国产欧美一区二区丝袜黑人 | 亚洲黄色免费在线观看| 午夜电影亚洲| 亚洲一区二区三区香蕉 | 久久久亚洲影院你懂的| 国产乱人乱偷精品视频a人人澡 | 亚洲精品人成| 男人最爱成人网| 精品视频中文字幕| 日韩成人免费在线观看| 粉嫩欧美一区二区三区高清影视| 在线观看成人免费| 伊人久久大香| 久久亚洲精品一区二区| 国产精品久久久久久久免费看| 欧美经典三级视频一区二区三区| 成人在线观看a| 天天久久夜夜| 欧美有码在线视频| 青青草免费在线| 色拍拍在线精品视频8848| 中文字幕一区二区人妻在线不卡| 久久av最新网址| 欧美精品与人动性物交免费看| 国产自产自拍视频在线观看| 亚洲精品美女免费| 中国一级特黄毛片| 久久先锋影音av鲁色资源| 国产中文字幕在线免费观看| 青青草原在线亚洲| 538国产精品一区二区在线| 亚洲 欧美 自拍偷拍| 色综合色狠狠综合色| 亚洲欧洲久久久| 蜜臀久久久99精品久久久久久| 手机在线观看国产精品| 99热这里有精品| 欧美床上激情在线观看| 欧美一级片免费| 欧美性生活大片免费观看网址| 国产在线观看h| 久久99国产精品成人| www国产无套内射com| 超碰精品在线观看| 欧美一区视频在线| av网站在线免费播放| 欧美一区二区三区爱爱| 日韩高清免费av| 国产欧美日本一区视频| 一本之道在线视频| 亚洲经典在线| 亚洲国产欧美日韩| 亚洲精品午夜| 国产精品爱久久久久久久| 麻豆传媒视频在线观看免费| 精品国产一区二区三区不卡 | 欧美男人的天堂一二区| 青青草手机在线视频| 91蜜桃网址入口| 不卡中文字幕在线观看| 亚洲看片一区| 在线观看成人av电影| 国产香蕉精品| 成人激情电影一区二区| www.综合| 不卡av电影院| 头脑特工队2在线播放| 欧美日韩亚洲综合一区| 亚洲国产精品午夜在线观看| 国产人久久人人人人爽| 69亚洲乱人伦| 久久福利视频一区二区| 五十路熟女丰满大屁股| 日本a口亚洲| 精品中文字幕一区| 91成人小视频| 国产精品视频自在线| 黄在线观看免费网站ktv| zzjj国产精品一区二区| 亚洲av成人精品日韩在线播放| 777亚洲妇女| 9i精品福利一区二区三区| 一区二区三区**美女毛片| 亚洲一区视频在线播放| 不卡在线观看av| 九九九九九九九九| 日韩精品91亚洲二区在线观看| 国产肉体ⅹxxx137大胆| 欧美黄色录像片| 欧美一区1区三区3区公司| 懂色av一区二区| 91美女片黄在线观| 国产精品4hu.www| 国产精品h片在线播放| av在线小说| 欧美激情三级免费| 成人在线网址| 深夜福利国产精品| 大片免费播放在线视频| 日韩精品欧美激情| 欧美一级性视频| 亚洲精品在线三区| 性欧美一区二区三区| 3d成人动漫网站| 国产露脸91国语对白| 欧美日韩在线播| 中文字字幕在线观看| 欧美午夜精品免费| 天天干天天操天天操| 欧美日韩在线视频一区二区| www.av麻豆| 天天综合日日夜夜精品| 国产在线视频第一页| 亚洲一区二区高清| 日本熟妇成熟毛茸茸| 亚洲网友自拍偷拍| av资源吧首页| 午夜精品久久久久影视| 国产成人无码一区二区三区在线 | 欧美精品在线免费| 最新黄网在线观看| 欧美精品在线免费播放| 韩国日本一区| 97国产精品视频| 麻豆免费在线| 国产精品jvid在线观看蜜臀| 992tv国产精品成人影院| 国产区亚洲区欧美区| 国产精品久久久久久久久久久久久久久| 国产欧美日韩中文字幕在线| 99er精品视频| 成人片在线免费看| 香蕉久久精品| 亚洲黄色成人久久久| 一区二区电影在线观看| 国产欧美日韩小视频| 日韩一级不卡| 一本久道中文无码字幕av| 日韩精品免费专区| 在线免费黄色网| 国产成人av一区二区三区在线| 日本黄色录像片| 久久久亚洲国产美女国产盗摄| 欧美xxxx精品| 亚洲一区日韩精品中文字幕| 日本中文字幕在线免费观看| 日本韩国欧美一区| 国产欧美第一页| 亚洲国产高潮在线观看| 国产视频第一区| 欧美成aaa人片免费看| 国产伦久视频在线观看| 国产精品欧美日韩| 亚洲日本va| 欧美资源一区| 欧美成人日本| 红桃av在线播放| 国产一级精品在线| 中出视频在线观看| 亚洲欧洲三级电影| 天天操天天摸天天干| 欧美日韩午夜精品| 欧美视频xxx| 色偷偷av一区二区三区| 高潮在线视频| 成人欧美一区二区三区黑人| 秋霞综合在线视频| 9l视频自拍9l视频自拍| 亚洲一区国产| 一区二区三区人妻| 国产日韩高清在线| 日韩精品一区三区| 欧美二区在线观看| 国产在线播放av| 久久久久久久久久久人体| 欧美91在线|欧美| 久久资源av| 欧美1区2区3区| 不卡的av中文字幕| 91麻豆123| 精品少妇久久久| 3d动漫精品啪啪一区二区竹菊 | 国产蜜臀av在线一区二区三区| 久久久夜色精品| 911精品国产一区二区在线| 欧美巨乳在线| 海角国产乱辈乱精品视频| 青草综合视频| 日本一区二区三区www| 亚洲三级毛片| 日本女人性视频| 亚洲欧洲精品一区二区精品久久久| 日本中文字幕在线| 欧美精品一区二区久久久| av在线免费网站| 91精品久久久久久久| 精品色999| 少妇人妻互换不带套| 99re这里只有精品首页| 国产一级视频在线| 欧美一二三在线| 在线视频观看国产| 91啪国产在线| 99久久99久久精品国产片桃花 | 欧美少妇在线观看| 麻豆国产一区二区| 一级黄色毛毛片| 欧美三级中文字| 成黄免费在线| 国产精品视频网址| 日韩欧美电影| 在线观看高清免费视频| 国产女主播在线一区二区| 亚洲乱码国产乱码精品| 国产视频欧美视频| 正在播放日韩精品| 欧美精品v日韩精品v国产精品| 亚洲视频大全| 中文字幕在线看高清电影| 欧美性猛交丰臀xxxxx网站| 久草在现在线| 国产精品国产自产拍高清av水多| 成人精品视频| 亚洲免费一级视频| 最新国产成人在线观看| 国产伦精品一区二区三区四区| 久久国产精品99国产精| 天堂va在线高清一区| 日韩视频在线视频| av在线不卡免费看| 日韩一区二区视频在线| 亚洲欧洲一区二区三区在线观看| 日本少妇一区| 日本成人性视频| 国产91精品精华液一区二区三区| 国产在线一区视频| 亚洲精品视频久久| 欧美另类激情| 日韩精品一区二区三区四| av在线不卡电影| 波多野结衣一区二区三区在线| 色老头一区二区三区在线观看| 国产高清精品二区| 日韩精品视频在线观看视频| 91麻豆国产精品久久| 亚洲天堂手机在线| 久久久久久久久久av| 岳的好大精品一区二区三区| 男女视频在线看| 一区二区三区成人在线视频| 色久视频在线播放| 成人在线观看视频网站| 亚洲另类视频| 国产精品suv一区二区88| 精品毛片乱码1区2区3区| 黑人巨大亚洲一区二区久| 国产精品99久久久久久大便| 99精品黄色片免费大全| 亚洲免费视频二区| 久久久久久久激情视频| 国产欧美日韩免费观看| 91在线第一页| 日韩欧美亚洲综合| 在线免费观看的av| 日韩一本精品| 成人av片在线观看| 在线免费观看日韩视频| 国内精品中文字幕| 91久久夜色精品国产按摩| 麻豆精品国产传媒av| 欧美二区乱c少妇| 我爱我色成人网| 久久综合久久久久|