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

高效數據隔離方案:SpringBoot+JSqlParser 全解析

數據庫 其他數據庫
通過在 prepare 方法進行攔截,我們可以在 SQL 語句被最終確定之前更改它,從而使修改生效。如果在 query 或 update 方法中進行攔截,則無法更改 SQL 語句,只能在執行前后進行其他操作,比如日志記錄或者結果處理。

在構建多租戶系統或需要數據權限控制的應用時,數據隔離是一個關鍵問題,而解決這一問題的有效方案之一是在項目的數據庫訪問層實現數據過濾。

本文將介紹如何在 Spring Boot 項目中利用Mybatis的強大攔截器機制結合JSqlParser —— 一個功能豐富的 SQL 解析器,來輕松實現數據隔離的目標。本文根據示例展示如何根據當前的運行環境來實現數據隔離。

工具介紹

Mybatis攔截器

Mybatis 支持在 SQL 執行的不同階段攔截并插入自定義邏輯。

本文將通過攔截 StatementHandler 接口的 prepare方法修改SQL語句,實現數據隔離的目的。

JSqlParser

JSqlParser 是一個開源的 SQL 語句解析工具,它可以對 SQL 語句進行解析、重構等各種操作:

  • 能夠將 SQL 字符串轉換成一個可操作的抽象語法樹(AST),這使得程序能夠理解和操作 SQL 語句的各個組成部分。
  • 根據需求對解析出的AST進行修改,比如添加額外的過濾條件,然后再將AST轉換回SQL字符串,實現需求定制化的SQL語句構建。

SELECT語法樹簡圖:

圖片

詳細步驟

1. 導入依賴

Mybatis 依賴:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

JSqlParser 依賴:

<dependency>
    <groupId>com.github.jsqlparser</groupId>
    <artifactId>jsqlparser</artifactId>
    <version>4.6</version>
</dependency>

注意:如果項目選擇了 Mybatis Plus 作為數據持久層框架,那么就無需另外添加 Mybatis 和 JSqlParser 的依賴。

Mybatis Plus 自身已經包含了這兩項依賴,并且保證了它們之間的兼容性。重復添加這些依賴可能會引起版本沖突,從而干擾項目的穩定性。

2. 定義一個攔截器

攔截所有 query 語句并在條件中加入 env 條件

import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.RowConstructor;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
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.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.statement.values.ValuesStatement;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
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.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.List;

@Component
@Intercepts(
        {
                @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
        }
)
public class DataIsolationInterceptor implements Interceptor {
    /**
     * 從配置文件中環境變量
     */
    @Value("${spring.profiles.active}")
    private String env;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        //確保只有攔截的目標對象是 StatementHandler 類型時才執行特定邏輯
        if (target instanceof StatementHandler) {
            StatementHandler statementHandler = (StatementHandler) target;
            // 獲取 BoundSql 對象,包含原始 SQL 語句
            BoundSql boundSql = statementHandler.getBoundSql();
            String originalSql = boundSql.getSql();
            String newSql = setEnvToStatement(originalSql);
            // 使用MetaObject對象將新的SQL語句設置到BoundSql對象中
            MetaObject metaObject = SystemMetaObject.forObject(boundSql);
            metaObject.setValue("sql", newSql);
        }
        // 執行SQL
        return invocation.proceed();
    }

    private String setEnvToStatement(String originalSql) {
        net.sf.jsqlparser.statement.Statement statement;
        try {
            statement = CCJSqlParserUtil.parse(originalSql);
        } catch (JSQLParserException e) {
            throw new RuntimeException("EnvironmentVariableInterceptor::SQL語句解析異常:"+originalSql);
        }
        if (statement instanceof Select) {
            Select select = (Select) statement;
            PlainSelect selectBody = select.getSelectBody(PlainSelect.class);
            if (selectBody.getFromItem() instanceof Table) {
                Expression newWhereExpression;
                if (selectBody.getJoins() == null || selectBody.getJoins().isEmpty()) {
                    newWhereExpression = setEnvToWhereExpression(selectBody.getWhere(), null);
                } else {
                    // 如果是多表關聯查詢,在關聯查詢中新增每個表的環境變量條件
                    newWhereExpression = multipleTableJoinWhereExpression(selectBody);
                }
                // 將新的where設置到Select中
                selectBody.setWhere(newWhereExpression);
            } else if (selectBody.getFromItem() instanceof SubSelect) {
                // 如果是子查詢,在子查詢中新增環境變量條件
                // 當前方法只能處理單層子查詢,如果有多層級的子查詢的場景需要通過遞歸設置環境變量
                SubSelect subSelect = (SubSelect) selectBody.getFromItem();
                PlainSelect subSelectBody = subSelect.getSelectBody(PlainSelect.class);
                Expression newWhereExpression = setEnvToWhereExpression(subSelectBody.getWhere(), null);
                subSelectBody.setWhere(newWhereExpression);
            }

            // 獲得修改后的語句
            return select.toString();
        } else if (statement instanceof Insert) {
            Insert insert = (Insert) statement;
            setEnvToInsert(insert);

            return insert.toString();
        } else if (statement instanceof Update) {
            Update update = (Update) statement;
            Expression newWhereExpression = setEnvToWhereExpression(update.getWhere(),null);
            // 將新的where設置到Update中
            update.setWhere(newWhereExpression);

            return update.toString();
        } else if (statement instanceof Delete) {
            Delete delete = (Delete) statement;
            Expression newWhereExpression = setEnvToWhereExpression(delete.getWhere(),null);
            // 將新的where設置到delete中
            delete.setWhere(newWhereExpression);

            return delete.toString();
        }
        return originalSql;
    }

    /**
     * 將需要隔離的字段加入到SQL的Where語法樹中
     * @param whereExpression SQL的Where語法樹
     * @param alias 表別名
     * @return 新的SQL Where語法樹
     */
    private Expression setEnvToWhereExpression(Expression whereExpression, String alias) {
        // 添加SQL語法樹的一個where分支,并添加環境變量條件
        AndExpression andExpression = new AndExpression();
        EqualsTo envEquals = new EqualsTo();
        envEquals.setLeftExpression(new Column(StringUtils.isNotBlank(alias) ? String.format("%s.env", alias) : "env"));
        envEquals.setRightExpression(new StringValue(env));
        if (whereExpression == null){
            return envEquals;
        } else {
            // 將新的where條件加入到原where條件的右分支樹
            andExpression.setRightExpression(envEquals);
            andExpression.setLeftExpression(whereExpression);
            return andExpression;
        }
    }

    /**
     * 多表關聯查詢時,給關聯的所有表加入環境隔離條件
     * @param selectBody select語法樹
     * @return 新的SQL Where語法樹
     */
    private Expression multipleTableJoinWhereExpression(PlainSelect selectBody){
        Table mainTable = selectBody.getFromItem(Table.class);
        String mainTableAlias = mainTable.getAlias().getName();
        // 將 t1.env = ENV 的條件添加到where中
        Expression newWhereExpression = setEnvToWhereExpression(selectBody.getWhere(), mainTableAlias);
        List<Join> joins = selectBody.getJoins();
        for (Join join : joins) {
            FromItem joinRightItem = join.getRightItem();
            if (joinRightItem instanceof Table) {
                Table joinTable = (Table) joinRightItem;
                String joinTableAlias = joinTable.getAlias().getName();
                // 將每一個join的 tx.env = ENV 的條件添加到where中
                newWhereExpression = setEnvToWhereExpression(newWhereExpression, joinTableAlias);
            }
        }
        return newWhereExpression;
    }

    /**
     * 新增數據時,插入env字段
     * @param insert Insert 語法樹
     */
    private void setEnvToInsert(Insert insert) {
        // 添加env列
        List<Column> columns = insert.getColumns();
        columns.add(new Column("env"));
        // values中添加環境變量值
        List<SelectBody> selects = insert.getSelect().getSelectBody(SetOperationList.class).getSelects();
        for (SelectBody select : selects) {
            if (select instanceof ValuesStatement){
                ValuesStatement valuesStatement = (ValuesStatement) select;
                ExpressionList expressions = (ExpressionList) valuesStatement.getExpressions();
                List<Expression> values = expressions.getExpressions();
                for (Expression expression : values){
                    if (expression instanceof RowConstructor) {
                        RowConstructor rowConstructor = (RowConstructor) expression;
                        ExpressionList exprList = rowConstructor.getExprList();
                        exprList.addExpressions(new StringValue(env));
                    }
                }
            }
        }
    }
}
3. 測試
  • Select

Mapper:

<select id="queryAllByOrgLevel" resultType="com.lyx.mybatis.entity.AllInfo">
    SELECT a.username,a.code,o.org_code,o.org_name,o.level
    FROM admin a left join organize o on a.org_id=o.id
    WHERE a.dr=0 and o.level=#{level}
</select>

剛進入攔截器時,Mybatis 解析的 SQL 語句:

SELECT a.username,a.code,o.org_code,o.org_name,o.level
        FROM admin a left join organize o on a.org_id=o.id
        WHERE a.dr=0 and o.level=?

執行完 setEnvToStatement(originalSql) 方法后,得到的新 SQL 語句:

SELECT a.username, a.code, o.org_code, o.org_name, o.level 
FROM admin a LEFT JOIN organize o ON a.org_id = o.id 
WHERE a.dr = 0 AND o.level = ? AND a.env = 'test' AND o.env = 'test'
  • Insert

剛進入攔截器時,Mybatis 解析的 SQL 語句:

INSERT INTO admin  ( id, username, code,   org_id )  VALUES (  ?, ?, ?,   ?  )

執行完 setEnvToInsert(insert) 方法后,得到的新 SQL 語句:

INSERT INTO admin (id, username, code, org_id, env) VALUES (?, ?, ?, ?, 'test')
  • Update

剛進入攔截器時,Mybatis 解析的 SQL 語句:

UPDATE admin  SET username=?, code=?,   org_id=?  WHERE id=?

執行完 setWhere(newWhereExpression) 方法后,得到的新 SQL 語句:

UPDATE admin SET username = ?, code = ?, org_id = ? WHERE id = ? AND env = 'test'
  • Delete

剛進入攔截器時,Mybatis 解析的 SQL 語句:

DELETE FROM admin WHERE id=?

執行完 setWhere(newWhereExpression) 方法后,得到的新 SQL 語句:

DELETE FROM admin WHERE id = ? AND env = 'test'
4. 為什么要攔截 StatementHandler 接口的 prepare 方法?

可以注意到,在這個例子中定義攔截器時 @Signature 注解中攔截的是 StatementHandler 接口的 prepare 方法,為什么攔截的是 prepare 方法而不是 query 和 update 方法?為什么攔截 query 和 update 方法修改 SQL 語句后仍然執行的是原 SQL ?關注公眾號:碼猿技術專欄,回復關鍵詞:1111 獲取阿里內部JVM調優手冊!

這是因為 SQL 語句是在 prepare 方法中被構建和參數化的。prepare 方法是負責準備 PreparedStatement 對象的,這個對象表示即將要執行的 SQL 語句。在 prepare 方法中可以對 SQL 語句進行修改,而這些修改將會影響最終執行的 SQL 。

而 query 和 update 方法是在 prepare 方法之后被調用的。它們主要的作用是執行已經準備好的 PreparedStatement 對象。在這個階段,SQL 語句已經被創建并綁定了參數值,所以攔截這兩個方法并不能改變已經準備好的 SQL 語句。

簡單來說,如果想要修改SQL語句的內容(比如增加 WHERE 子句、改變排序規則等),那么需要在 SQL 語句被準備之前進行攔截,即在 prepare 方法的執行過程中進行。

以下是 MyBatis 執行過程中的幾個關鍵步驟:

  1. 解析配置和映射文件: MyBatis 啟動時,首先加載配置文件和映射文件,解析里面的 SQL 語句。
  2. 生成 StatementHandler 和 BoundSql: 當執行一個操作,比如查詢或更新時,MyBatis 會創建一個 StatementHandler 對象,并包裝了 BoundSql 對象,后者包含了即將要執行的 SQL 語句及其參數。
  3. 執行 prepare 方法: StatementHandler 的 prepare 方法被調用,完成 PreparedStatement 的創建和參數設置。
  4. 執行 query 或 update: 根據執行的是查詢操作還是更新操作,MyBatis 再調用 query 或 update 方法來實際執行 SQL 。

通過在 prepare 方法進行攔截,我們可以在 SQL 語句被最終確定之前更改它,從而使修改生效。如果在 query 或 update 方法中進行攔截,則無法更改 SQL 語句,只能在執行前后進行其他操作,比如日志記錄或者結果處理。

責任編輯:武曉燕 來源: 碼猿技術專欄
相關推薦

2011-09-14 10:09:02

負載均衡網站架構緩存

2014-12-24 10:47:20

施耐德綠色數據中心

2025-06-13 01:22:00

2022-01-14 14:50:14

SpringBootymlJava

2022-01-13 17:24:04

SpringBootYml監聽器

2025-06-26 02:11:00

2023-06-07 13:50:00

SaaS多租戶系統

2021-09-16 17:21:02

安超云云計算物聯網

2011-03-29 18:09:43

2023-02-15 18:31:48

數據存儲隔離

2018-11-28 15:15:52

大數據AI安防

2022-03-09 21:55:30

HBase數據入倉

2025-05-14 03:00:00

2019-07-28 21:05:47

ICMPIP網絡協議

2014-10-27 14:09:01

華為

2015-05-13 15:15:16

HadoopHBaseMapReduce

2025-06-23 04:00:00

接口SpringToken

2015-03-27 17:07:47

敏捷數據中心全聯接SD華為

2011-09-14 10:56:52

服務器虛擬化數據中心
點贊
收藏

51CTO技術棧公眾號

√天堂资源在线| 欧美日韩国产精品一区二区| 中文字幕在线2021| 成人av综合网| 欧美网站在线观看| 亚洲国产精品综合| 成人免费观看在线视频| 日韩成人一级片| 欧美成人精品一区| 亚洲人人夜夜澡人人爽| 色8久久久久| 精品日本高清在线播放| 亚洲一卡二卡区| 少妇无码一区二区三区| 麻豆成人久久精品二区三区红 | 国产精品igao视频| 日韩精品欧美精品| 亚洲一区中文字幕在线| 黄色成年人视频在线观看| 国产麻豆成人传媒免费观看| 69国产精品成人在线播放| 岛国片在线免费观看| 精品欧美午夜寂寞影院| 欧美老女人第四色| 黄色www网站| sm国产在线调教视频| 久久久精品欧美丰满| 国产超碰91| 亚洲影院一区二区三区| 国产亚洲亚洲| 久久久久久com| 日本黄色免费片| 免费在线毛片网站| 99国产精品久久久久| 亚洲va久久久噜噜噜| 乱子伦一区二区三区| 9国产精品视频| 久久久久久999| 欧美黄色免费观看| 亚洲区综合中文字幕日日| 亚洲男人天堂2023| 99久久久无码国产精品性波多| 亚洲视频资源| 欧美人伦禁忌dvd放荡欲情| 男女激情无遮挡| 成年网站在线视频网站| 亚洲日本丝袜连裤袜办公室| 亚洲精品中文字幕乱码三区不卡| 日本一区二区三区在线观看视频| av电影在线观看完整版一区二区| 91在线看网站| 国产精品一品二区三区的使用体验| 日韩精品欧美精品| 国产精品视频地址| 一二区在线观看| 久久国产精品一区二区| 国产精品入口夜色视频大尺度 | 一个色在线综合| 国产精品免费看久久久无码| 色婷婷视频在线观看| 一区二区三区四区在线| 99久热在线精品视频| 牛牛电影国产一区二区| 亚洲.国产.中文慕字在线| 日韩av中文字幕第一页| 蜜臀av午夜精品| 成人午夜激情片| 国产精品一区二区不卡视频| 色窝窝无码一区二区三区成人网站| 国产91露脸合集magnet| 国产丝袜不卡| 日本视频在线观看一区二区三区| 26uuu另类欧美亚洲曰本| 蜜桃网站成人| av中文字幕在线| 最近日韩中文字幕| 日韩免费在线观看av| 亚洲精华液一区二区三区| 欧美色视频日本版| 伊人国产在线视频| 国产一区 二区| 日韩av一区二区在线观看| 亚洲精品女人久久久| 精品视频黄色| 欧美大片va欧美在线播放| 国产精品a成v人在线播放| 亚洲免费网站| 91精品国产综合久久久久久久久| 成人av无码一区二区三区| 91最新地址在线播放| 台湾成人av| 国产精品久久久久久福利| 一二三区精品福利视频| 亚洲人成色77777| 国产精品视频一区二区三区| 日韩精品在线免费观看| 精品人妻一区二区三区四区| 国产毛片一区二区三区| 在线性视频日韩欧美| 青娱乐国产在线视频| 日韩专区一卡二卡| 国产精品毛片va一区二区三区| 美女毛片在线看| 一区二区三区成人| 中文字幕在线观看第三页| 亚洲电影一区| 精品在线观看入口| 一本大道久久a久久综合| 免费一区二区三区在线观看| 国产劲爆久久| 久久人人爽人人爽人人片亚洲| 久久久午夜影院| 国产综合久久久久久鬼色| 欧美不卡在线一区二区三区| 成人av黄色| 91福利精品第一导航| 91成人在线观看喷潮蘑菇| 日韩欧美在线中字| 欧美亚洲在线视频| 亚洲经典一区二区| 最新高清无码专区| 牛夜精品久久久久久久| 精品综合久久88少妇激情| 久久天堂电影网| 亚洲国产无线乱码在线观看| 97se狠狠狠综合亚洲狠狠| 国产 国语对白 露脸| 国产精品久久久久久妇女| 日韩激情在线视频| 久久精品国产亚洲av高清色欲| 精品在线亚洲视频| 午夜精品一区二区在线观看| 亚洲人体影院| 日韩av在线精品| 久久久美女视频| 国产一区二区三区久久悠悠色av| 午夜精品一区二区在线观看| av在线不卡精品| 国产午夜精品全部视频在线播放| 国产精品久久久免费视频| 高清国产午夜精品久久久久久| 好色先生视频污| 四虎影视成人精品国库在线观看 | 欧美亚州韩日在线看免费版国语版| 国产xxxx视频| 99国产精品99久久久久久粉嫩| 成人h视频在线观看| 新版中文在线官网| 精品捆绑美女sm三区| 强行糟蹋人妻hd中文| 国产精品亚洲а∨天堂免在线| 国产高潮呻吟久久久| 亚洲精品三区| 久久中文字幕国产| 国产成人精品a视频| 亚洲黄网站在线观看| 激情小说欧美色图| 99riav1国产精品视频| 蜜桃久久精品乱码一区二区| 亚洲综合电影| 亚洲网站在线播放| 在线视频播放大全| 亚洲摸摸操操av| 日本成人在线免费| 亚洲日本免费| 久久久神马电影| 欧美日韩国产网站| 久久精品免费电影| 粉嫩av一区二区夜夜嗨| 欧美日韩午夜剧场| 性欧美精品男男| 国内成人精品2018免费看| 奇米777四色影视在线看| 大香伊人久久精品一区二区| 欧美性受xxx| 福利视频在线导航| 欧美一区二区美女| 日本中文字幕网| 国产欧美一区二区精品婷婷| av中文字幕网址| 黄色亚洲大片免费在线观看| 久久精品国产美女| 日本精品久久| 欧美极品少妇xxxxx| 蜜桃视频在线播放| 日韩一区二区精品| 特一级黄色大片| 中文字幕日韩精品一区| 少妇被狂c下部羞羞漫画| 肉肉av福利一精品导航| 日本道在线视频| 亚州精品视频| 成人一区二区电影| 忘忧草在线日韩www影院| www国产精品视频| 免费观看黄一级视频| 欧洲一区在线观看| 日本一区二区不卡在线| 自拍偷拍亚洲欧美日韩| 国产三级国产精品| 国产精品综合一区二区| www.欧美日本| 亚洲人成人一区二区三区| 亚洲精品永久www嫩草| 国产精品一线| 成人做爰www免费看视频网站| 日韩伦理精品| 色中色综合影院手机版在线观看| 免费理论片在线观看播放老| 日韩免费高清视频| 欧美激情一区二区三区免费观看| 婷婷夜色潮精品综合在线| 性生交大片免费全黄| 久久久久国产成人精品亚洲午夜| 韩国三级在线看| 久久99精品国产| 毛片一区二区三区四区| 亚洲夜间福利| 欧美少妇一区二区三区| 欧美gayvideo| 视频二区一区| 九一国产精品| 久久久久久草| 国产成人高清精品免费5388| 91欧美视频网站| 韩国精品视频在线观看 | 成人午夜精品久久久久久久蜜臀| 久久看人人摘| 色综合久久88色综合天天提莫| 日韩欧美中文字幕电影| 国产精品一区在线观看| 午夜久久av| 超碰在线97av| 一区二区三区免费在线看| 91深夜福利视频| 欧美一级网址| 成人观看高清在线观看免费| 日韩一区二区三区四区五区| 国产日韩精品在线播放| 青青热久免费精品视频在线18| 国产成人亚洲精品| 人人鲁人人莫人人爱精品| 奇米4444一区二区三区| 日韩脚交footjobhd| 日本久久精品视频| 少妇av在线播放| 日韩一区二区在线观看视频| 国产又大又长又粗| 7777精品伊人久久久大香线蕉经典版下载 | 先锋资源久久| 日本黄色播放器| 66视频精品| 日本精品福利视频| 欧美日韩亚洲国产精品| av在线免费观看国产| 亚洲性色视频| 日本精品免费在线观看| 久久综合亚州| 欧美成人福利在线观看| 国产在线精品一区二区不卡了| 91aaa精品| 国产91色综合久久免费分享| 国产毛片毛片毛片毛片毛片毛片| www.欧美精品一二区| 国产ts丝袜人妖系列视频| 久久久久久97三级| 黄色一级片一级片| 玉足女爽爽91| 日韩一区二区视频在线| 91九色最新地址| 91黄色在线视频| 日韩久久精品一区| 视频一区二区三区在线看免费看| 亚洲日韩中文字幕| 麻豆影视国产在线观看| 欧美乱人伦中文字幕在线| aaa在线播放视频| 国产91免费观看| 91麻豆精品国产91久久久更新资源速度超快| 91精品中国老女人| 欧美丝袜足交| 五月天亚洲综合| 在线精品福利| 中文字幕一区二区三区四区在线视频| 狠狠色狠狠色合久久伊人| 又黄又爽的网站| 中文字幕中文字幕在线一区| 久久一二三四区| 日本高清视频一区二区| 国产ts变态重口人妖hd| 亚洲精品中文字幕女同| 国产最新在线| 欧美亚洲视频在线看网址| 自拍偷拍亚洲图片| 久久免费看av| 亚洲人体av| 国产a视频免费观看| 国产一区视频在线看| 美女100%无挡| 亚洲一区在线观看免费| 波多野结衣爱爱| 精品国产乱码久久久久久蜜臀| 国产精品免费观看| 欧美激情精品久久久久久免费印度| 日韩天堂在线| 国产欧美日韩亚洲| 66视频精品| 天天色综合天天色| 91免费国产在线观看| a级黄色片免费看| 欧美三日本三级三级在线播放| 色婷婷av一区二区三区之红樱桃 | 激情高潮到大叫狂喷水| 午夜av一区二区| 国产福利资源在线| 色999日韩欧美国产| 制服丝袜第一页在线观看| 污污在线观看| 日韩日本欧美亚洲| 少妇在线看www| 成人综合av网| 亚洲成av人电影| 亚洲综合色在线观看| 26uuu亚洲综合色欧美| 国产亚洲欧美久久久久 | 国产又色又爽又黄又免费| 亚洲欧美国产精品久久久久久久 | www视频在线观看免费| 97成人精品视频在线观看| 视频一区日韩精品| 欧美一级免费在线观看| 蜜臀va亚洲va欧美va天堂| 播金莲一级淫片aaaaaaa| 亚洲va韩国va欧美va| 精品国产区一区二| 欧美xxxx18性欧美| 国产精品一区二区精品视频观看| 新呦u视频一区二区| 日韩av电影免费观看高清完整版| 爱爱免费小视频| 黑人精品xxx一区一二区| 婷婷色在线观看| 96精品视频在线| 天天躁日日躁狠狠躁欧美| 欧美 国产 综合| 久久综合久久99| 无码人妻久久一区二区三区不卡| 日韩国产精品一区| 国模冰冰炮一区二区| 欧美一区二区三区四区夜夜大片 | 天天综合亚洲| 99中文字幕在线| 樱花草国产18久久久久| 午夜精品久久久久久久96蜜桃| 久99九色视频在线观看| 99久久香蕉| 国产肥臀一区二区福利视频| 久久综合九色综合久久久精品综合| 99热只有这里有精品| 亚洲精选中文字幕| 亚洲欧美韩国| 色中色综合成人| 国产精品中文字幕日韩精品| 免费视频网站www| 日韩成人在线视频观看| 亚州一区二区三区| 亚洲日本精品国产第一区| 国产一区日韩二区欧美三区| 免费三片在线播放| 日韩精品中文字幕在线| 欧美日韩精品一区二区三区视频| 亚洲精品一区二区三区av| 国产麻豆精品在线| 久久精品这里有| 亚洲午夜激情免费视频| 国内精品视频| 999在线观看视频| 国产免费观看久久| 国产三级伦理片| 97av视频在线| 青青一区二区三区| 免费看91视频| 91精品福利在线| 91精品久久| 免费精品视频一区| 精品一区二区三区在线观看国产| 免费在线一级片| 国产一区二区三区在线观看视频| а天堂中文最新一区二区三区| 日本男女交配视频| 国产偷国产偷亚洲高清人白洁| 国产精品伦一区二区三区| 国内偷自视频区视频综合| 欧美精品一二| 白嫩情侣偷拍呻吟刺激| 欧美性一区二区| sm在线观看| 特级毛片在线免费观看| 91捆绑美女网站| 国产理论视频在线观看|