日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

认真看看, 以后写 SQL 就爽多了:MyBatis 动态 SQL

發布時間:2025/3/20 数据库 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 认真看看, 以后写 SQL 就爽多了:MyBatis 动态 SQL 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊上方?好好學java?,選擇?星標?公眾號

重磅資訊、干貨,第一時間送達今日推薦:2020年7月程序員工資統計,平均14357元,又跌了,扎心個人原創100W+訪問量博客:點擊前往,查看更多

整理:阿進的寫字臺

原文:cnblogs.com/homejim/p/9909657.html

MyBatis 令人喜歡的一大特性就是動態 SQL。在使用 JDBC 的過程中, 根據條件進行 SQL 的拼接是很麻煩且很容易出錯的。MyBatis 動態 SQL 的出現, 解決了這個麻煩。

MyBatis通過 OGNL 來進行動態 SQL 的使用的。

目前, 動態 SQL 支持以下幾種標簽

元素作用備注
if判斷語句單條件分支
choose(when、otherwise)相當于 Java 中的 if else多條件分支
trim(where、set)輔助元素用于處理 SQL 拼接問題
foreach循環語句批量插入, 更新, 查詢時經常用到
bind創建一個變量, 并綁定到上下文中用于兼容不同的數據庫, 防止 SQL 注入等

1 數據準備

為了后面的演示, 創建了一個 Maven 項目 mybatis-dynamic, 創建了對應的數據庫和表

DROP?TABLE?IF?EXISTS?`student`;CREATE?TABLE?`student`?(`student_id`?int(10)?unsigned?NOT?NULL?AUTO_INCREMENT?COMMENT?'編號',`name`?varchar(20)?DEFAULT?NULL?COMMENT?'姓名',`phone`?varchar(20)?DEFAULT?NULL?COMMENT?'電話',`email`?varchar(50)?DEFAULT?NULL?COMMENT?'郵箱',`sex`?tinyint(4)?DEFAULT?NULL?COMMENT?'性別',`locked`?tinyint(4)?DEFAULT?NULL?COMMENT?'狀態(0:正常,1:鎖定)',`gmt_created`?datetime?DEFAULT?CURRENT_TIMESTAMP?COMMENT?'存入數據庫的時間',`gmt_modified`?datetime?DEFAULT?CURRENT_TIMESTAMP?ON?UPDATE?CURRENT_TIMESTAMP?COMMENT?'修改的時間',`delete`?int(11)?DEFAULT?NULL,PRIMARY?KEY?(`student_id`) )?ENGINE=InnoDB?AUTO_INCREMENT=7?DEFAULT?CHARSET=utf8mb4?COLLATE=utf8mb4_0900_ai_ci?COMMENT='學生表';

對應的項目結構

項目結構

2 if 標簽

if 標簽是我們最常使用的。在查詢、刪除、更新的時候很可能會使用到。必須結合 test 屬性聯合使用。

2.1 在 WHERE 條件中使用 if 標簽

這是常見的一種現象, 我們在進行按條件查詢的時候, 可能會有多種情況。

2.1.1 查詢條件

根據輸入的學生信息進行條件檢索

  • 當只輸入用戶名時, 使用用戶名進行模糊檢索;

  • 當只輸入性別時, 使用性別進行完全匹配

  • 當用戶名和性別都存在時, 用這兩個條件進行查詢匹配查詢

  • 2.1.2 動態 SQL

    接口函數

    ????/***?根據輸入的學生信息進行條件檢索* 1. 當只輸入用戶名時,?使用用戶名進行模糊檢索;*?2.?當只輸入郵箱時,?使用性別進行完全匹配*?3.?當用戶名和性別都存在時,?用這兩個條件進行查詢匹配的用*?@param?student*?@return*/List<Student>?selectByStudentSelective(Student?student);

    對應的動態 SQL

    ??<select?id="selectByStudentSelective"?resultMap="BaseResultMap"?parameterType="com.homejim.mybatis.entity.Student">select<include?refid="Base_Column_List"?/>from?studentwhere?1=1<if?test="name?!=?null?and?name?!=''">and?name?like?concat('%',?#{name},?'%')</if><if?test="sex?!=?null">and?sex=#{sex}</if></select>

    在此 SQL 語句中, where 1=1 是多條件拼接時的小技巧, 后面的條件查詢就可以都用 and 了。

    同時, 我們添加了 if 標簽來處理動態 SQL

    ????<if?test="name?!=?null?and?name?!=''">and?name?like?concat('%',?#{name},?'%')</if><if?test="sex?!=?null">and?sex=#{sex}</if>

    此 if 標簽的 test 屬性值是一個符合 OGNL 的表達式, 表達式可以是 true 或 false。如果表達式返回的是數值, 則0為 false, 非 0 為 true;

    2.1.3 測試

    ??????@Testpublic?void?selectByStudent()?{SqlSession?sqlSession?=?null;sqlSession?=?sqlSessionFactory.openSession();StudentMapper?studentMapper?=?sqlSession.getMapper(StudentMapper.class);Student?search?=?new?Student();search.setName("明");System.out.println("只有名字時的查詢");List<Student>?studentsByName?=?studentMapper.selectByStudentSelective(search);for?(int?i?=?0;?i?<?studentsByName.size();?i++)?{System.out.println(ToStringBuilder.reflectionToString(studentsByName.get(i),?ToStringStyle.MULTI_LINE_STYLE));}search.setName(null);search.setSex((byte)?1);System.out.println("只有性別時的查詢");List<Student>?studentsBySex?=?studentMapper.selectByStudentSelective(search);for?(int?i?=?0;?i?<?studentsBySex.size();?i++)?{System.out.println(ToStringBuilder.reflectionToString(studentsBySex.get(i),?ToStringStyle.MULTI_LINE_STYLE));}System.out.println("姓名和性別同時存在的查詢");search.setName("明");List<Student>?studentsByNameAndSex?=?studentMapper.selectByStudentSelective(search);for?(int?i?=?0;?i?<?studentsByNameAndSex.size();?i++)?{System.out.println(ToStringBuilder.reflectionToString(studentsByNameAndSex.get(i),?ToStringStyle.MULTI_LINE_STYLE));}sqlSession.commit();sqlSession.close();}

    只有名字時的查詢, 發送的語句和結果

    只有名字時的查詢

    查詢的條件只發送了

    where?1=1?and?name?like?concat('%',??,?'%')?

    只有性別時的查詢, 發送的語句和結果

    只有性別時的查詢

    查詢的條件只發送了

    ?where?1=1?and?sex=??

    姓名和性別同時存在的查詢, 發送的語句和結果

    姓名和性別同時存在的查詢

    查詢條件

    where?1=1?and?name?like?concat('%',??,?'%')?and?sex=??

    2.2 在 UPDATE 更新列中使用 if 標簽

    有時候我們不希望更新所有的字段, 只更新有變化的字段。

    2.2.1 更新條件

    只更新有變化的字段, 空值不更新。

    2.2.1 動態 SQL

    接口方法

    ????/***?更新非空屬性*/int?updateByPrimaryKeySelective(Student?record);

    對應的 SQL

    ??<update?id="updateByPrimaryKeySelective"?parameterType="com.homejim.mybatis.entity.Student">update?student<set><if?test="name?!=?null">`name`?=?#{name,jdbcType=VARCHAR},</if><if?test="phone?!=?null">phone?=?#{phone,jdbcType=VARCHAR},</if><if?test="email?!=?null">email?=?#{email,jdbcType=VARCHAR},</if><if?test="sex?!=?null">sex?=?#{sex,jdbcType=TINYINT},</if><if?test="locked?!=?null">locked?=?#{locked,jdbcType=TINYINT},</if><if?test="gmtCreated?!=?null">gmt_created?=?#{gmtCreated,jdbcType=TIMESTAMP},</if><if?test="gmtModified?!=?null">gmt_modified?=?#{gmtModified,jdbcType=TIMESTAMP},</if></set>where?student_id?=?#{studentId,jdbcType=INTEGER}

    2.2.3 測試

    ????@Testpublic?void?updateByStudentSelective()?{SqlSession?sqlSession?=?null;sqlSession?=?sqlSessionFactory.openSession();StudentMapper?studentMapper?=?sqlSession.getMapper(StudentMapper.class);Student?student?=?new?Student();student.setStudentId(1);student.setName("明明");student.setPhone("13838438888");System.out.println(studentMapper.updateByPrimaryKeySelective(student));sqlSession.commit();sqlSession.close();}

    結果如下

    在 UPDATE 更新列中使用 if 標簽

    2.3 在 INSERT 動態插入中使用 if 標簽

    我們插入數據庫中的一條記錄, 不是每一個字段都有值的, 而是動態變化的。在這時候使用 if 標簽, 可幫我們解決這個問題。

    2.3.1 插入條件

    只有非空屬性才插入。

    2.3.2 動態SQL

    接口方法

    ????/***?非空字段才進行插入*/int?insertSelective(Student?record);

    對應的SQL

    <insert?id="insertSelective"?parameterType="com.homejim.mybatis.entity.Student">insert?into?student<trim?prefix="("?suffix=")"?suffixOverrides=","><if?test="studentId?!=?null">student_id,</if><if?test="name?!=?null">`name`,</if><if?test="phone?!=?null">phone,</if><if?test="email?!=?null">email,</if><if?test="sex?!=?null">sex,</if><if?test="locked?!=?null">locked,</if><if?test="gmtCreated?!=?null">gmt_created,</if><if?test="gmtModified?!=?null">gmt_modified,</if></trim><trim?prefix="values?("?suffix=")"?suffixOverrides=","><if?test="studentId?!=?null">#{studentId,jdbcType=INTEGER},</if><if?test="name?!=?null">#{name,jdbcType=VARCHAR},</if><if?test="phone?!=?null">#{phone,jdbcType=VARCHAR},</if><if?test="email?!=?null">#{email,jdbcType=VARCHAR},</if><if?test="sex?!=?null">#{sex,jdbcType=TINYINT},</if><if?test="locked?!=?null">#{locked,jdbcType=TINYINT},</if><if?test="gmtCreated?!=?null">#{gmtCreated,jdbcType=TIMESTAMP},</if><if?test="gmtModified?!=?null">#{gmtModified,jdbcType=TIMESTAMP},</if></trim></insert>

    這個 SQL 大家應該很熟悉, 畢竟是自動生成的。

    2.3.3 測試

    ????@Testpublic?void?insertByStudentSelective()?{SqlSession?sqlSession?=?null;sqlSession?=?sqlSessionFactory.openSession();StudentMapper?studentMapper?=?sqlSession.getMapper(StudentMapper.class);Student?student?=?new?Student();student.setName("小飛機");student.setPhone("13838438899");student.setEmail("xiaofeiji@qq.com");student.setLocked((byte)?0);System.out.println(studentMapper.insertSelective(student));sqlSession.commit();sqlSession.close();}

    對應的結果

    在 INSERT 動態插入中使用 if 標簽

    SQL 中, 只有非空的字段才進行了插入。

    3 choose 標簽

    choose when otherwise 標簽可以幫我們實現 if else 的邏輯。

    一個 choose 標簽至少有一個 when, 最多一個otherwise

    下面是一個查詢的例子。

    3.1 查詢條件

    假設 name 具有唯一性, 查詢一個學生

    • 當 studen_id 有值時, 使用 studen_id 進行查詢;

    • 當 studen_id 沒有值時, 使用 name 進行查詢;

    • 否則返回空

    3.2 動態SQL

    接口方法

    ????/***?-?當 studen_id 有值時,?使用 studen_id 進行查詢;*?-?當 studen_id 沒有值時,?使用 name 進行查詢;*?-?否則返回空*/Student?selectByIdOrName(Student?record);

    對應的SQL

    ??<select?id="selectByIdOrName"?resultMap="BaseResultMap"?parameterType="com.homejim.mybatis.entity.Student">select<include?refid="Base_Column_List"?/>from?studentwhere?1=1<choose><when?test="studentId?!=?null">and?student_id=#{studentId}</when><when?test="name?!=?null?and?name?!=?''">and?name=#{name}</when><otherwise>and?1=2</otherwise></choose></select>

    3.3 測試

    ?@Testpublic?void?selectByIdOrName()?{SqlSession?sqlSession?=?null;sqlSession?=?sqlSessionFactory.openSession();StudentMapper?studentMapper?=?sqlSession.getMapper(StudentMapper.class);Student?student?=?new?Student();student.setName("小飛機");student.setStudentId(1);Student?studentById?=?studentMapper.selectByIdOrName(student);System.out.println("有?ID?則根據?ID?獲取");System.out.println(ToStringBuilder.reflectionToString(studentById,?ToStringStyle.MULTI_LINE_STYLE));student.setStudentId(null);Student?studentByName?=?studentMapper.selectByIdOrName(student);System.out.println("沒有?ID?則根據?name?獲取");System.out.println(ToStringBuilder.reflectionToString(studentByName,?ToStringStyle.MULTI_LINE_STYLE));student.setName(null);Student?studentNull?=?studentMapper.selectByIdOrName(student);System.out.println("沒有?ID?和?name,?返回?null");Assert.assertNull(studentNull);sqlSession.commit();sqlSession.close();}

    有 ID 則根據 ID 獲取, 結果

    有 ID 則根據 ID 獲取

    沒有 ID 則根據 name 獲取

    沒有 ID 則根據 name 獲取

    沒有 ID 和 name, 返回 null

    沒有 ID 和 name, 返回 null

    4 trim(set、where)

    這三個其實解決的是類似的問題。如我們在寫前面的[在 WHERE 條件中使用 if 標簽] SQL 的時候, where 1=1 這個條件我們是不希望存在的。

    4.1 where

    4.1.1 查詢條件

    根據輸入的學生信息進行條件檢索。

  • 當只輸入用戶名時, 使用用戶名進行模糊檢索;

  • 當只輸入性別時, 使用性別進行完全匹配

  • 當用戶名和性別都存在時, 用這兩個條件進行查詢匹配查詢

  • 不使用 where 1=1

    4.1.2 動態 SQL

    很顯然, 我們要解決這幾個問題

    • 當條件都不滿足時:此時 SQL 中應該要不能有 where , 否則導致出錯

    • 當 if 有條件滿足時:SQL 中需要有 where, 且第一個成立的 if 標簽下的 and | or 等要去掉

    這時候, 我們可以使用 where 標簽。

    接口方法

    ????/***?根據輸入的學生信息進行條件檢索* 1. 當只輸入用戶名時,?使用用戶名進行模糊檢索;*?2.?當只輸入郵箱時,?使用性別進行完全匹配*?3.?當用戶名和性別都存在時,?用這兩個條件進行查詢匹配的用*/List<Student>?selectByStudentSelectiveWhereTag(Student?student);

    對應的 SQL

    ??<select?id="selectByStudentSelectiveWhereTag"?resultMap="BaseResultMap"?parameterType="com.homejim.mybatis.entity.Student">select<include?refid="Base_Column_List"?/>from?student<where><if?test="name?!=?null?and?name?!=''">and?name?like?concat('%',?#{name},?'%')</if><if?test="sex?!=?null">and?sex=#{sex}</if></where></select>

    4.1.3 測試

    ????@Testpublic?void?selectByStudentWhereTag()?{SqlSession?sqlSession?=?null;sqlSession?=?sqlSessionFactory.openSession();StudentMapper?studentMapper?=?sqlSession.getMapper(StudentMapper.class);Student?search?=?new?Student();search.setName("明");System.out.println("只有名字時的查詢");List<Student>?studentsByName?=?studentMapper.selectByStudentSelectiveWhereTag(search);for?(int?i?=?0;?i?<?studentsByName.size();?i++)?{System.out.println(ToStringBuilder.reflectionToString(studentsByName.get(i),?ToStringStyle.MULTI_LINE_STYLE));}search.setSex((byte)?1);System.out.println("姓名和性別同時存在的查詢");List<Student>?studentsBySex?=?studentMapper.selectByStudentSelectiveWhereTag(search);for?(int?i?=?0;?i?<?studentsBySex.size();?i++)?{System.out.println(ToStringBuilder.reflectionToString(studentsBySex.get(i),?ToStringStyle.MULTI_LINE_STYLE));}System.out.println("姓名和性別都不存在時查詢");search.setName(null);search.setSex(null);List<Student>?studentsByNameAndSex?=?studentMapper.selectByStudentSelectiveWhereTag(search);for?(int?i?=?0;?i?<?studentsByNameAndSex.size();?i++)?{System.out.println(ToStringBuilder.reflectionToString(studentsByNameAndSex.get(i),?ToStringStyle.MULTI_LINE_STYLE));}sqlSession.commit();sqlSession.close();}

    只有名字時的查詢, 有 where

    只有名字時的查詢

    姓名和性別同時存在的查詢, 有 where

    姓名和性別同時存在的查詢

    姓名和性別都不存在時查詢, 此時, where 不會再出現了。

    姓名和性別都不存在時查詢

    4.2 set

    set 標簽也類似, 在 [2.2 在 UPDATE 更新列中使用 if 標簽] 中, 如果我們的方法 updateByPrimaryKeySelective 沒有使用 標簽, 那么我們就要想辦法處理字段全為空的條件, 字段不為空的條件等。有了這個, 我們只需要寫 if 標簽即可, 不需要處理類似的問題。

    4.3 trim

    set 和 where 其實都是 trim 標簽的一種類型, 該兩種功能都可以使用 trim 標簽進行實現。

    4.3.1 trim 來表示 where

    如以上的 where 標簽, 我們也可以寫成

    <trim?prefix="where"?prefixOverrides="AND?|OR"> </trim>

    表示當 trim 中含有內容時, 添加 where, 且第一個為 and 或 or 時, 會將其去掉。而如果沒有內容, 則不添加 where。

    4.3.2 trim 來表示 set

    相應的, set 標簽可以如下表示

    <trim?prefix="SET"?suffixOverrides=","> </trim>

    表示當 trim 中含有內容時, 添加 set, 且最后的內容為 , 時, 會將其去掉。而沒有內容, 不添加 set

    4.3.3 trim 的幾個屬性

    • prefix: 當 trim 元素包含有內容時, 增加 prefix 所指定的前綴

    • prefixOverrides: 當 trim 元素包含有內容時, 去除 prefixOverrides 指定的 前綴

    • suffix: 當 trim 元素包含有內容時, 增加 suffix 所指定的后綴

    • suffixOverrides:當 trim 元素包含有內容時, 去除 suffixOverrides 指定的后綴

    5 foreach 標簽

    foreach 標簽可以對數組, Map 或實現 Iterable 接口。

    foreach 中有以下幾個屬性

    • collection: 必填, 集合/數組/Map的名稱.

    • item: 變量名。即從迭代的對象中取出的每一個值

    • index: 索引的屬性名。當迭代的對象為 Map 時, 該值為 Map 中的 Key.

    • open: 循環開頭的字符串

    • close: 循環結束的字符串

    • separator: 每次循環的分隔符

    其他的比較好理解, collection 中的值應該怎么設定呢?

    跟接口方法中的參數相關。

    1. 只有一個數組參數或集合參數

    默認情況:集合collection=list, 數組是collection=array

    推薦:使用 @Param 來指定參數的名稱, 如我們在參數前@Param("ids"), 則就填寫 collection=ids

    2. 多參數

    多參數請使用 @Param 來指定, 否則SQL中會很不方便

    3. 參數是Map

    指定為 Map 中的對應的 Key 即可。其實上面的 @Param 最后也是轉化為 Map 的。

    4. 參數是對象

    使用屬性.屬性即可。

    5.1 在 where 中使用 foreach

    在 where條件中使用, 如按id集合查詢, 按id集合刪除等。

    5.1.1 查詢條件

    我們希望查詢用戶 id 集合中的所有用戶信息。

    5.1.2 動態 SQL

    函數接口

    ????/***?獲取?id?集合中的用戶信息*?@param?ids*?@return*/List<Student>?selectByStudentIdList(List<Integer>?ids);

    對應 SQL

    ??<select?id="selectByStudentIdList"?resultMap="BaseResultMap">select<include?refid="Base_Column_List"?/>from?studentwhere?student_id?in<foreach?collection="list"?item="id"?open="("?close=")"?separator=","?index="i">#{id}</foreach></select>

    5.1.3 測試

    ????@Testpublic?void?selectByStudentIdList()?{SqlSession?sqlSession?=?null;sqlSession?=?sqlSessionFactory.openSession();StudentMapper?studentMapper?=?sqlSession.getMapper(StudentMapper.class);List<Integer>?ids?=?new?LinkedList<>();ids.add(1);ids.add(3);List<Student>?students?=?studentMapper.selectByStudentIdList(ids);for?(int?i?=?0;?i?<?students.size();?i++)?{System.out.println(ToStringBuilder.reflectionToString(students.get(i),?ToStringStyle.MULTI_LINE_STYLE));}sqlSession.commit();sqlSession.close();}

    結果

    在 where 中使用 foreach

    5.2 foreach 實現批量插入

    可以通過foreach來實現批量插入。

    5.2.1 動態SQL

    接口方法

    ????/***?批量插入學生*/int?insertList(List<Student>?students);

    對應的SQL

    ??<insert?id="insertList">insert?into?student(name,?phone,?email,?sex,?locked)values<foreach?collection="list"?item="student"?separator=",">(#{student.name},?#{student.phone},#{student.email},#{student.sex},#{student.locked})</foreach></insert>

    5.2.2 測試

    ????@Testpublic?void?insertList()?{SqlSession?sqlSession?=?null;sqlSession?=?sqlSessionFactory.openSession();StudentMapper?studentMapper?=?sqlSession.getMapper(StudentMapper.class);List<Student>?students?=?new?LinkedList<>();Student?stu1?=?new?Student();stu1.setName("批量01");stu1.setPhone("13888888881");stu1.setLocked((byte)?0);stu1.setEmail("13888888881@138.com");stu1.setSex((byte)?1);students.add(stu1);Student?stu2?=?new?Student();stu2.setName("批量02");stu2.setPhone("13888888882");stu2.setLocked((byte)?0);stu2.setEmail("13888888882@138.com");stu2.setSex((byte)?0);students.add(stu2);System.out.println(studentMapper.insertList(students));sqlSession.commit();sqlSession.close();}

    結果

    foreach 實現批量插入

    6 bind 標簽

    bind 標簽是通過 OGNL 表達式去定義一個上下文的變量, 這樣方便我們使用。

    如在 selectByStudentSelective 方法中, 有如下

    <if?test="name?!=?null?and?name?!=''">and?name?like?concat('%',?#{name},?'%')</if>

    在 MySQL 中, 該函數支持多參數, 但在 Oracle 中只支持兩個參數。那么我們可以使用 bind 來讓該 SQL 達到支持兩個數據庫的作用

    <if?test="name?!=?null?and?name?!=''"><bind?name="nameLike"?value="'%'+name+'%'"/>and?name?like?#{nameLike} </if>

    更改后的查詢結果如下

    bind 標簽的使用

    最后最后,大家有沒有 Star 過什么沙雕項目?有的話告訴我,我分享給大家。

    最后,再附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,筆者這幾年及春招的總結,github 1.4k star,拿去不謝!

    下載方式1.?首先掃描下方二維碼2.?后臺回復「Java面試」即可獲取

    總結

    以上是生活随笔為你收集整理的认真看看, 以后写 SQL 就爽多了:MyBatis 动态 SQL的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: missav在线| 色97色| 日本五十路在线 | 黄网站在线免费 | av鲁丝一区鲁丝二区鲁丝三区 | 蜜桃精品噜噜噜成人av | 中国大陆高清aⅴ毛片 | 一级片在线视频 | 成年人视频网址 | 视频精品一区二区 | 成人动漫在线播放 | 日韩免费观看一区二区三区 | 91精品国产色综合久久不卡蜜臀 | 日本一二三区在线视频 | 国产精品6666| 99国产精品人妻噜啊噜 | 性感美女被爆操 | 7799精品视频 | av黄在线| 精品裸体舞一区二区三区 | 国产黄色精品网站 | 一级视频在线观看 | 亚洲第一二三区 | 5个黑人躁我一个视频 | 女同动漫免费观看高清完整版在线观看 | 黄色片在线看 | 久久中文字幕一区二区 | 国产精品一线二线三线 | 精品国产户外野外 | 夜夜骚网站| 亚洲午夜伦理 | www.国产视频| 在线综合色| 国产精品扒开腿做爽爽 | 中文字幕乱码中文乱码b站 国产一区二区三区在线观看视频 | 以女性视角写的高h爽文 | 国产精品人妻一区二区三区 | 开心成人激情 | 无码人妻丰满熟妇区bbbbxxxx | 伊人久久av | 国产精品美女久久久久图片 | 国产精品二区一区二区aⅴ污介绍 | 九九热re | 精品久久国产字幕高潮 | 黄色片地址 | 国产精品久久777777 | 国产模特av私拍大尺度 | 久久精品国产亚洲a | 亚洲AV无码久久精品浪潮 | 污污内射在线观看一区二区少妇 | 黄色大片免费观看 | 一区精品在线观看 | 午夜激情视频在线播放 | 无法忍受在线观看 | 久久久久久国产精品视频 | 国产精品夜色一区二区三区 | 免费观看一区二区三区毛片 | 桃色91| 性猛交ⅹxxx富婆视频 | 久久中文字幕国产 | 国产在线不卡 | 国产精品白丝喷水在线观看 | 亚洲人成人 | 日韩精品导航 | 日韩中文一区 | 日韩在线视频网站 | 天天摸天天碰天天爽天天弄 | aaaaaa毛片| 嫩草视频在线看 | 逼特逼在线视频 | 日韩黄网 | 四虎国产精品永久免费观看视频 | 中文字幕乱码人妻二区三区 | 欧美aa在线观看 | 日韩深夜在线 | 欧美精品久久久久久久久老牛影院 | 在线日本视频 | 深夜国产福利 | 名人明星三级videos | 91鲁| 久久久久久久国产精品美女 | 精品一区在线播放 | 亚洲一区精品在线观看 | 草草在线视频 | 成人在线观看免费高清 | 天天5g天天爽免费观看 | 538国产精品一区二区免费视频 | 日韩伦理一区二区三区 | 手机在线看黄色 | 亚洲视频你懂的 | 污视频在线网站 | 精品久久久久久无码中文野结衣 | 亚洲一区二区三区在线 | 美女搡bbb又爽又猛又黄www | 99精品在线 | 中文字幕第一 | 久久亚洲视频 | 国产91精品一区二区麻豆亚洲 | 国产精品高清网站 |