亚洲有码Av一区二区三区_国产高清啪啪免费视频_69色视频国产_国产成人人人爆出白浆_国产精品自在线拍国_一本久久伊人热热精品无码_午夜性刺激在线看免费带字幕_助力高品质欧美狂喷水_亚洲精品日韩无码_精品无码一区二区三区蜜臀_麻豆高清国产AV_熟妇人素无码中文字幕_亚洲a级片在线观看_国产欧美日韩三区_99国产成人高清在线观看

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營(yíng)的一線實(shí)戰(zhàn)洞察。

MyBatis-Plus 單測(cè) lambda 緩存報(bào)錯(cuò)根因與五種修復(fù)方案

MyBatis-Plus 單測(cè) lambda 緩存報(bào)錯(cuò)根因與五種修復(fù)方案 上周三下午CI 上一條原本跑得好好的流水線突然變紅日志里躺著這么一行can not find lambda cache for this entity [com.example.demo.entity.User]。第一反應(yīng)是代碼合錯(cuò)了回滾重跑——還是紅。本地 IDEA 里點(diǎn)一下單測(cè)綠的。把 CI 上失敗的那個(gè)測(cè)試類單獨(dú)拎到本地跑也綠。折騰了半個(gè)小時(shí)才發(fā)現(xiàn)問(wèn)題出在一個(gè)新同事加的ArgumentCaptor上他為了斷言參數(shù)把LambdaQueryWrapper打印了出來(lái)于是 MyBatis-Plus 第一次真正去渲染 SQL 片段結(jié)果在純 Mockito 環(huán)境里實(shí)體對(duì)應(yīng)的 lambda 緩存壓根沒被注冊(cè)過(guò)。這個(gè)場(chǎng)景應(yīng)該很多人撞過(guò)。用 Mockito 給 MyBatisPlus 的 Service 或 Mapper 做單元測(cè)試平時(shí)只when(...).thenReturn(...)的時(shí)候一切正常一旦某個(gè)環(huán)節(jié)觸碰到了Wrapper的 SQL 渲染、或者用真實(shí) SqlSession 走了 H2就會(huì)蹦出can not find lambda cache。它既不是 Mockito 的 bug也不是 MyBatisPlus 的 bug純屬兩套機(jī)制在隔離的測(cè)試環(huán)境里沒接上頭。下面我把這條報(bào)錯(cuò)從堆棧到根因、從修復(fù)方案到完整實(shí)操按我自己踩坑的順序捋一遍涉及 Mockito、MyBatisPlus、lambda 緩存、分頁(yè)攔截、IRepository泛型這幾塊不管你剛學(xué)單元測(cè)試還是已經(jīng)在寫測(cè)試覆蓋率卡口都能直接拿去用。1. 別急著改代碼先把這個(gè)錯(cuò)定位清楚1.1 從堆棧反推異常究竟是誰(shuí)拋的先看完整的堆棧長(zhǎng)什么樣這一步能省掉后面大量的猜測(cè)com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: can not find lambda cache for this entity [com.example.demo.entity.User] at com.baomidou.mybatisplus.core.toolkit.Assert.notNull(Assert.java:xx) at com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper.tryInitCache(AbstractLambdaWrapper.java:xx) at com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper.getColumn(AbstractLambdaWrapper.java:xx) at com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper.columnToString(AbstractLambdaWrapper.java:xx) at com.baomidou.mybatisplus.core.conditions.AbstractLambdaWrapper.lambda$columnToSqlSegment$0(...) at com.baomidou.mybatisplus.core.conditions.AbstractWrapper.getSqlSegment(AbstractWrapper.java:xx) at com.baomidou.mybatisplus.core.conditions.AbstractWrapper.getTargetSql(AbstractWrapper.java:xx) at com.example.demo.UserServiceImplTest.pageByAge(UserServiceImplTest.java:xx)堆棧信息量很大。關(guān)鍵在AbstractLambdaWrapper#tryInitCache它是整個(gè) lambda 解析鏈路上唯一會(huì)拋這個(gè)斷言的地方。往上看一層是getColumn再往上是columnToString而它的調(diào)用者是一個(gè)包裹了columnToSqlSegment的 lambda 表達(dá)式這個(gè)表達(dá)式只有在getSqlSegment()被真正執(zhí)行時(shí)才跑起來(lái)。換句話說(shuō)這個(gè)異常不是構(gòu)造 Wrapper 的那一刻拋的而是Wrapper 需要拼 SQL 的那一刻拋的。這一點(diǎn)極其重要因?yàn)樗忉屃藶槭裁从行┤说膯螠y(cè)一直沒事?lián)Q個(gè)斷言方式就炸了。兩個(gè)測(cè)試類可能寫著幾乎一樣的when(mapper.selectList(any())).thenReturn(list)唯一的差別是一個(gè)只斷言返回值另一個(gè)順手打印了一下 wrapper 的 SQL結(jié)果后者紅前者綠。我在排查時(shí)習(xí)慣先做一件事把報(bào)錯(cuò)那一行的實(shí)體類名抄下來(lái)然后在工程里全局搜這個(gè)類確認(rèn)它有沒有加TableName。遇到過(guò)兩次實(shí)體類是從別的模塊復(fù)制過(guò)來(lái)的、TableName忘了帶本地跑集成測(cè)試時(shí)因?yàn)殚_了table-prefix也能湊合單測(cè)里就現(xiàn)原形。搜實(shí)體類是成本最低的一步排查。1.2 為什么本地跑得好好的一到單測(cè)環(huán)境就翻車要理解這件事得先知道 MyBatisPlus 是怎么工作的。它對(duì)待LambdaQueryWrapper的方式和對(duì)待QueryWrapper完全不同QueryWrapper用的是字符串列名wrapper.eq(user_name, 張三)里的user_name直接就是 SQL 片段MyBatisPlus 不需要查任何東西。而LambdaQueryWrapper用的是方法引用wrapper.eq(User::getUserName, 張三)里的User::getUserName只是一個(gè) Java 的SFunctionMyBatisPlus 必須把它翻譯成數(shù)據(jù)庫(kù)列名user_name。這個(gè)翻譯動(dòng)作靠的是一張映射表屬性名 → 列名。這張表不是憑空來(lái)的。啟動(dòng)階段MyBatisPlus 掃描 Mapper 接口、解析泛型、拿到實(shí)體類然后由TableInfoHelper逐個(gè)實(shí)體解析注解、拼出完整的TableInfo表名、主鍵、所有字段的TableField、邏輯刪除字段、樂觀鎖字段、自動(dòng)填充字段最后把每個(gè)實(shí)體的屬性名到 ColumnCache的映射塞進(jìn)LambdaUtils維護(hù)的一個(gè)靜態(tài)ConcurrentHashMap里。這個(gè)動(dòng)作叫installCache。SpringBootTest或者真實(shí)啟動(dòng)應(yīng)用時(shí)Spring 拉起 MyBatisPlus 的自動(dòng)配置Mapper 被掃描TableInfoHelper老老實(shí)實(shí)跑完了所有實(shí)體緩存滿滿當(dāng)當(dāng)LambdaQueryWrapper隨便用。而純 Mockito 單測(cè)里沒有 Spring 上下文、沒有 Mapper 掃描、沒有SqlSessionFactoryTableInfoHelper一次都沒被調(diào)用那個(gè)靜態(tài) Map 是空的。等你真的去解析 lambda 的時(shí)候查不到實(shí)體對(duì)應(yīng)的條目Assert.notNull就拋出來(lái)了。它本質(zhì)上是個(gè)環(huán)境缺失問(wèn)題不是邏輯錯(cuò)誤。理解到這一層后面的幾個(gè)修復(fù)方案就都是同一個(gè)思路的不同實(shí)現(xiàn)想辦法把那一步初始化在單測(cè)里補(bǔ)上。1.3 哪些寫法會(huì)真的觸發(fā)這個(gè)異常我把自己和同事碰到過(guò)的情況整理成一張表你可以對(duì)著自己的測(cè)試代碼掃一眼測(cè)試?yán)锏膶懛〞?huì)觸發(fā) SQL 渲染嗎會(huì)不會(huì)報(bào) lambda cache 錯(cuò)構(gòu)造 wrapper 后直接傳給 mock 的 mappermapper 返回固定值不會(huì)不會(huì)when(mapper.selectList(any())).thenReturn(list)不會(huì)不會(huì)斷言wrapper.getTargetSql()或getSqlSegment()會(huì)會(huì)用ArgumentCaptor抓 wrapper然后打印或斷言 SQL會(huì)會(huì)thenAnswer里手動(dòng)調(diào)invocation.getArgument(0).getSqlSegment()會(huì)會(huì)測(cè)試?yán)镒约捍盍?SqlSessionFactory走 H2 真庫(kù)會(huì)會(huì)Service 內(nèi)部對(duì) wrapper 做了二次加工比如取getSqlSelect()會(huì)會(huì)單測(cè)里手動(dòng)調(diào)分頁(yè)攔截器的beforeQuery做驗(yàn)證會(huì)會(huì)日志切面在方法返回時(shí)把 wrapper 打進(jìn)日志會(huì)會(huì)這張表第一次看到的時(shí)候我有點(diǎn)意外原來(lái)絕大多數(shù)看著像會(huì)炸的寫法其實(shí)根本不炸。很多人寫單測(cè)時(shí)用的都是前兩行的模式所以一直相安無(wú)事直到某天為了排查參數(shù)問(wèn)題加了個(gè) SQL 打印或者為了驗(yàn)證 SQL 拼接對(duì)不對(duì)加了斷言才第一次見到這個(gè)錯(cuò)。這也解釋了一個(gè)現(xiàn)象——同一個(gè)測(cè)試類別人跑綠你跑紅很可能不是環(huán)境差異而是你的斷言更嚴(yán)格。提示如果你只是想快速確認(rèn)是不是這個(gè)原因在報(bào)錯(cuò)的地方往上找getTargetSql或getSqlSegment十有八九就在你的測(cè)試代碼里躺著。2. 把 lambda 緩存這條鏈路徹底拆開2.1 一行方法引用到底經(jīng)歷了什么User::getUserName在 Java 里是一個(gè)編譯期生成的 lambda 實(shí)例。如果你的目標(biāo)類型是SFunctionUser, ?MyBatisPlus 自己的函數(shù)式接口繼承自Serializable那么編譯器會(huì)為它生成一個(gè)帶有writeReplace方法的內(nèi)部類。這個(gè)方法返回一個(gè)SerializedLambda對(duì)象里面記錄了這段 lambda 的全部元信息implClass實(shí)現(xiàn)類名、implMethodName方法名這里是getUserName、instantiatedMethodType實(shí)例化后的方法簽名等等。MyBatisPlus 的LambdaUtils.extract(SFunction)做的就是這件事反射調(diào)用writeReplace把SerializedLambda摳出來(lái)。這一步不需要任何緩存隨時(shí)可用。接下來(lái)是兩步關(guān)鍵轉(zhuǎn)換從implMethodName里把getUserName變成屬性名userName。這一步由PropertyNamer.methodToProperty完成規(guī)則跟 JavaBean 一致去掉get、首字母小寫isXxx開頭的 boolean getter 也支持lambda$開頭的方法名會(huì)做特殊處理。用屬性名去緩存里查對(duì)應(yīng)的ColumnCache拿到真正的列名user_name和查詢別名getColumnSelect形如user_name AS userName。第二步就是那個(gè)緩存唯一存在的地方。緩存是Map實(shí)體類, Map屬性名, ColumnCache的結(jié)構(gòu)不同版本內(nèi)部實(shí)現(xiàn)略有差異早期按類名字符串做 key后來(lái)改成 Class 對(duì)象它由TableInfoHelper在初始化實(shí)體時(shí)通過(guò)LambdaUtils.installCache(tableInfo)寫入。所以整條鏈路是SFunction→SerializedLambda→ 方法名 → 屬性名 → 緩存查詢 → 列名。前四步都是純計(jì)算最后一步才是需要初始化的地方。緩存沒寫進(jìn)去前面全白搭。2.2TableInfoHelper在什么時(shí)候把緩存寫進(jìn)去正常啟動(dòng)流程里TableInfoHelper的調(diào)用點(diǎn)很隱蔽MyBatisPlus 的MybatisMapperAnnotationBuilder在解析每個(gè) Mapper 接口時(shí)會(huì)拿 Mapper 的泛型參數(shù)調(diào)TableInfoHelper.initTableInfo(builderAssistant, entityClass)。也就是說(shuō)實(shí)體緩存的初始化是被 Mapper 掃描順帶觸發(fā)的只要你的 Mapper 被掃到實(shí)體就會(huì)被注冊(cè)。這帶來(lái)一個(gè)很反直覺的推論一個(gè)實(shí)體如果沒有對(duì)應(yīng)的 Mapper 接口它在生產(chǎn)環(huán)境里其實(shí)也是沒有緩存的。所以有時(shí)候你新建了一個(gè)只用來(lái)接 DTO 的實(shí)體放在entity包下、沒有寫 Mapper然后在某個(gè)工具類里用了Wrappers.lambdaQuery(那個(gè)實(shí)體)運(yùn)行時(shí)照樣報(bào)這個(gè)錯(cuò)。這個(gè)問(wèn)題和 Matlab 那種沒聲明就報(bào)未定義有點(diǎn)像——不是語(yǔ)法問(wèn)題是注冊(cè)問(wèn)題。再補(bǔ)一個(gè)細(xì)節(jié)initTableInfo內(nèi)部對(duì)同一個(gè)實(shí)體是冪等的它先查自己的TABLE_INFO_CACHE已經(jīng)存在就直接返回不會(huì)重復(fù)解析注解。這意味著你可以在測(cè)試基類、BeforeAll、BeforeEach里反復(fù)調(diào)不用擔(dān)心副作用唯一的代價(jià)是第一次的那點(diǎn)反射開銷。同時(shí)它也是靜態(tài)全局的同一個(gè) JVM 里所有測(cè)試類共享所以如果你是多模塊 Maven 構(gòu)建、Surefire 會(huì) fork 多個(gè) JVM緩存是不共享的每個(gè) fork 都要自己初始化一遍。這一點(diǎn)在排查為什么單跑綠、全量跑紅的時(shí)候尤其要注意。2.3 版本差異別照著過(guò)時(shí)博客抄 APIMyBatisPlus 3.5.x 的小版本迭代非常密集lambda 緩存這塊的類名和方法名變過(guò)好幾次這也是為什么你在網(wǎng)上搜到的解決方案抄到自己工程里編譯不過(guò)。我手上這個(gè) 3.5.3.1緩存入口在com.baomidou.mybatisplus.core.toolkit.LambdaUtils取緩存的方法叫g(shù)etColumnMap(Class)緩存值的類型是ColumnCache在toolkit.support包下面。而 3.5.4 之后TableInfo自己增加了columnMap和fieldColumnMap兩個(gè)字段LambdaUtils上的取緩存方法名調(diào)整成了getColumnCacheColumnCache的包路徑也挪了位置。如果你搜到的方案里寫的是LambdaUtils.getColumnMap而你的依賴是 3.5.7那編譯不過(guò)很正常。注意涉及 MyBatisPlus 內(nèi)部 API 的代碼第一件事是打開 IDE按住 Ctrl 點(diǎn)進(jìn)LambdaUtils看源碼確認(rèn)你當(dāng)前版本的方法簽名。我見過(guò)太多人因?yàn)閺?fù)制了一個(gè)不匹配的版本號(hào)在initTableInfo的參數(shù)順序上卡了一下午——老版本是(Configuration, String namespace, Class)新版本是(MapperBuilderAssistant, Class)看著像參數(shù)順序完全不一樣。我個(gè)人的做法是把 MyBatisPlus 的版本鎖死在父 pom 的dependencyManagement里測(cè)試基類里用到的內(nèi)部 API 全部加一行注釋說(shuō)明此寫法適配 3.5.3.x升級(jí)需復(fù)核。這樣別人升級(jí)依賴時(shí)至少會(huì)看到提示不至于某天 CI 突然全紅還找不到人。3. 五種修復(fù)方案我挨個(gè)試了一遍3.1 方案一手動(dòng)調(diào)用initTableInfo最輕量這是我最推薦的方案改動(dòng)量極小只依賴mybatis-plus-core不需要引入任何 Spring 測(cè)試上下文跑起來(lái)是毫秒級(jí)。核心就三行代碼MybatisConfiguration configuration new MybatisConfiguration(); MapperBuilderAssistant assistant new MapperBuilderAssistant(configuration, ); TableInfoHelper.initTableInfo(assistant, User.class);MapperBuilderAssistant是 MyBatis 原生的類用來(lái)在構(gòu)建期輔助解析MybatisConfiguration是 MyBatisPlus 對(duì) MyBatisConfiguration的擴(kuò)展里面注冊(cè)了 MyBatisPlus 需要的LanguageDriver和類型處理器。第二個(gè)參數(shù)是resource傳空字符串就夠了它只用于錯(cuò)誤提示和日志。為什么選這兩個(gè)類而不是自己 new 一個(gè)Configuration因?yàn)門ableInfoHelper.initTableInfo內(nèi)部會(huì)調(diào)GlobalConfigUtils.getGlobalConfig(builderAssistant.getConfiguration())去拿全局配置涉及主鍵策略、邏輯刪除默認(rèn)值、字段自動(dòng)填充這些而GlobalConfigUtils內(nèi)部對(duì)一個(gè)非MybatisConfiguration的實(shí)例也能勉強(qiáng)工作但在某些版本上會(huì)走到不一致的分支。用MybatisConfiguration是最保險(xiǎn)的。這里有個(gè)真實(shí)的坑值得單獨(dú)說(shuō)GlobalConfigUtils內(nèi)部用configuration.toString()作為全局配置緩存的 key。MybatisConfiguration沒有重寫toString所以每次new出來(lái)的實(shí)例 key 都不一樣每次初始化都會(huì)往那個(gè)靜態(tài) Map 里塞一個(gè)新條目。單測(cè)場(chǎng)景下總共就那么幾個(gè)測(cè)試類無(wú)所謂但如果你在BeforeEach里每次 new 一個(gè)新的MybatisConfiguration幾百個(gè)用例跑下來(lái)會(huì)留幾百個(gè)GlobalConfig對(duì)象不放。所以我在測(cè)試基類里把MybatisConfiguration和MapperBuilderAssistant都做成static final全局共用一個(gè)實(shí)例。3.2 方案二MybatisPlusTest官方給的切片測(cè)試姿勢(shì)從 3.5.3 開始MyBatisPlus 提供了一個(gè)獨(dú)立的測(cè)試模塊mybatis-plus-boot-starter-test里面有個(gè)注解MybatisPlusTest。它的定位和 Spring Boot 的DataJpaTest、WebMvcTest一樣屬于切片測(cè)試只啟動(dòng) MyBatis 相關(guān)的那一層不加載整個(gè)應(yīng)用上下文。MybatisPlusTest class UserMapperTest { Autowired private UserMapper userMapper; Test void testSelectByLambda() { LambdaQueryWrapperUser wrapper Wrappers.UserlambdaQuery() .eq(User::getUserName, 張三); ListUser users userMapper.selectList(wrapper); assertThat(users).isNotNull(); } }這個(gè)方案最大的好處是Mapper 是真的TableInfo是自動(dòng)初始化的你不需要手動(dòng)管理緩存而且能順帶驗(yàn)證 SQL 在真實(shí)數(shù)據(jù)庫(kù)上跑得通。MybatisPlusTest默認(rèn)會(huì)用內(nèi)嵌數(shù)據(jù)庫(kù)替換掉項(xiàng)目的 DataSource所以你得在測(cè)試依賴?yán)锛由?H2 或者 HSQLDB否則啟動(dòng)時(shí)找不到可用數(shù)據(jù)源會(huì)直接報(bào)錯(cuò)。它的缺點(diǎn)也很明確這是集成測(cè)試不是單元測(cè)試。啟動(dòng)一次上下文大概幾百毫秒到一秒如果用它覆蓋所有 Service 方法整個(gè)測(cè)試套件的執(zhí)行時(shí)間會(huì)從幾十秒漲到幾分鐘。我一般的分配是Mapper 層、復(fù)雜 SQL、分頁(yè)邏輯用MybatisPlusTestService 的業(yè)務(wù)分支參數(shù)校驗(yàn)、異常拋出、緩存判斷、事務(wù)邊界用純 Mockito 單測(cè)。兩層各司其職覆蓋率反而更實(shí)。3.3 方案三SpringBootTestMockBean最貼近生產(chǎn)如果項(xiàng)目本身就有一整套 Spring Boot 測(cè)試腳手架最省事的做法是在原有測(cè)試類上加SpringBootTest讓完整的自動(dòng)配置跑一遍緩存自然就有了然后把你需要隔離的外部依賴第三方接口、Redis、消息隊(duì)列用MockBean替掉。SpringBootTest class UserServiceImplSpringTest { Autowired private UserService userService; MockBean private UserMapper userMapper; Test void pageByAge_should_return_empty_when_no_data() { PageUser mockPage new Page(1, 10); mockPage.setRecords(Collections.emptyList()); mockPage.setTotal(0L); when(userMapper.selectPage(any(), any())).thenReturn(mockPage); PageUser result userService.pageByAge(20, 1, 10); assertThat(result.getRecords()).isEmpty(); } }注意這里MockBean替換的是 Mapper而 Service 是真實(shí)的 Spring Bean。這個(gè)組合下 lambda 緩存是齊的因?yàn)樗鼘儆谏舷挛某跏蓟囊徊糠指?Mapper 是不是 mock 無(wú)關(guān)。這是它比方案一穩(wěn)的地方。代價(jià)是啟動(dòng)慢而且有個(gè)隱蔽的坑MockBean會(huì)污染 Spring 的上下文緩存。Spring 的測(cè)試框架會(huì)為不同的MockBean組合創(chuàng)建不同的上下文如果一個(gè)模塊里每個(gè)測(cè)試類的MockBean都不一樣上下文緩存命中率極低跑一輪測(cè)試可能啟動(dòng)十幾個(gè)完整的 Spring 上下文。解決思路是把MockBean的定義收斂到基類里同一個(gè)模塊的測(cè)試類盡量共用同一套 mock 集合。3.4 方案四換成QueryWrapper字符串列名臨時(shí)兜底如果只是某個(gè)工具類的單測(cè)卡在這里短期內(nèi)又不想動(dòng)測(cè)試基建最粗暴的辦法是把LambdaQueryWrapper換成QueryWrapper用字符串列名QueryWrapperUser wrapper new QueryWrapperUser() .eq(user_name, 張三) .orderByDesc(id);這條路繞開了 lambda 解析自然也就繞開了緩存一定能跑通。但我把它排在第四位原因是它解決的是測(cè)試的問(wèn)題破壞的是代碼的一致性生產(chǎn)代碼里用 lambda 保證編譯期類型安全測(cè)試?yán)镉米址忻坏┳侄沃孛鸌DE 重構(gòu)會(huì)改到生產(chǎn)代碼改不到測(cè)試代碼測(cè)試悄悄失效。如果確實(shí)要用我的建議是只在一個(gè)很小的、明確標(biāo)注// TODO 臨時(shí)方案待測(cè)試基建補(bǔ)齊后回退的方法里用并且用常量而不是裸字符串// 和實(shí)體字段一一對(duì)應(yīng)用 Lombok 的 FieldNameConstants 生成 QueryWrapperUser wrapper new QueryWrapperUser() .eq(User.Fields.userName, 張三);Lombok 從 1.18.4 開始提供FieldNameConstants生成的字符串常量在字段重命名時(shí)會(huì)跟著變能補(bǔ)回來(lái)一部分安全性。這個(gè)折中方案我在遷移老項(xiàng)目的時(shí)候用過(guò)效果還行。3.5 方案五mockStatic硬改LambdaUtils知道就好還有一種技術(shù)流的解法用 Mockito 的靜態(tài) mock 能力把LambdaUtils的取緩存方法直接打樁返回一個(gè)手工構(gòu)造的 Maptry (MockedStaticLambdaUtils mocked Mockito.mockStatic(LambdaUtils.class)) { MapString, ColumnCache fakeCache new HashMap(); fakeCache.put(userName, new ColumnCache(user_name, user_name AS userName)); mocked.when(() - LambdaUtils.getColumnMap(User.class)).thenReturn(fakeCache); // 執(zhí)行測(cè)試 }這個(gè)寫法有幾個(gè)致命問(wèn)題第一ColumnCache的構(gòu)造簽名在不同版本里不一樣編譯期就可能掛第二靜態(tài) mock 是全局生效的如果你用了 JUnit 5 的并行測(cè)試其他線程的用例會(huì)受影響必須嚴(yán)格放在 try-with-resources 里第三它需要mockito-inlineMockito 5.x 之后已經(jīng)內(nèi)置為默認(rèn) mock maker不用單獨(dú)引老版本項(xiàng)目加這個(gè)依賴可能引起別的行為變化。所以我把這個(gè)方案列出來(lái)只是為了讓你在看到一個(gè)開源項(xiàng)目這么寫的時(shí)候不至于懵實(shí)際落地我一次都沒用過(guò)。緩存初始化本身只需要三行代碼沒必要用靜態(tài) mock 去對(duì)抗它。五個(gè)方案橫向?qū)Ρ确桨竼?dòng)開銷是否需要 Spring與生產(chǎn)環(huán)境一致性推薦場(chǎng)景手動(dòng)initTableInfo極低毫秒級(jí)否中僅緩存層一致Service 業(yè)務(wù)邏輯單測(cè)首選MybatisPlusTest中幾百毫秒是高M(jìn)yBatis 層完整Mapper 層、分頁(yè)、復(fù)雜 SQLSpringBootTestMockBean高1 秒以上是最高需要驗(yàn)證 Bean 裝配、事務(wù)、切面換QueryWrapper無(wú)否低臨時(shí)兜底不推薦長(zhǎng)期用mockStatic低否低只建議在閱讀源碼時(shí)理解不建議落地4. 完整跑一遍UserServiceImpl的單測(cè)怎么寫4.1 依賴清單和版本先把 pom 里需要的東西列清楚。這里刻意只列測(cè)試相關(guān)的生產(chǎn)依賴按你自己的項(xiàng)目來(lái)。properties mybatis-plus.version3.5.3.1/mybatis-plus.version mockito.version4.11.0/mockito.version junit.version5.9.3/junit.version /properties dependencies dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version${mybatis-plus.version}/version /dependency !-- 純 Mockito 單測(cè)只需要 core -- dependency groupIdorg.mockito/groupId artifactIdmockito-core/artifactId version${mockito.version}/version scopetest/scope /dependency dependency groupIdorg.mockito/groupId artifactIdmockito-junit-jupiter/artifactId version${mockito.version}/version scopetest/scope /dependency !-- 需要靜態(tài) mock 或 final 類的 mock 才加Mockito 5 已內(nèi)置 -- dependency groupIdorg.mockito/groupId artifactIdmockito-inline/artifactId version${mockito.version}/version scopetest/scope /dependency !-- 用 MybatisPlusTest 才需要 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter-test/artifactId version${mybatis-plus.version}/version scopetest/scope /dependency dependency groupIdcom.h2database/groupId artifactIdh2/artifactId version2.1.214/version scopetest/scope /dependency /dependencies有一點(diǎn)要提醒mockito-inline在 Mockito 5.x 里已經(jīng)被合并進(jìn)mockito-core默認(rèn)的 mock maker 就是 inline 的。如果你的項(xiàng)目還用著 Spring Boot 2.x 帶來(lái)的 Mockito 4.x那就得顯式引如果你已經(jīng)在 Spring Boot 3.x看到別人 pom 里還留著mockito-inline反而會(huì)互相沖突最好確認(rèn)一下。4.2 被測(cè)代碼和實(shí)體實(shí)體設(shè)計(jì)得稍微復(fù)雜一點(diǎn)把幾個(gè)容易踩坑的點(diǎn)都覆蓋上Data TableName(t_user) public class User { TableId(type IdType.AUTO) private Long id; private String userName; private Integer age; /** 字段名是數(shù)據(jù)庫(kù)關(guān)鍵字需要轉(zhuǎn)義 */ TableField(desc) private String desc; TableLogic private Integer deleted; TableField(exist false) private String extraInfo; }這里塞了三個(gè)典型場(chǎng)景desc是 MySQL 的關(guān)鍵字需要反引號(hào)轉(zhuǎn)義MyBatisPlus 的TableField會(huì)把它寫進(jìn)ColumnCachedeleted加了TableLogic初始化時(shí)會(huì)被識(shí)別成邏輯刪除字段extraInfo加了TableField(exist false)它不會(huì)進(jìn)入列名映射所以你不能用User::getExtraInfo去構(gòu)造查詢條件用了照樣報(bào)找不到對(duì)應(yīng)列或者直接報(bào)緩存問(wèn)題。Service 層public interface UserService extends IServiceUser { PageUser pageByAge(Integer age, long current, long size); } Service public class UserServiceImpl extends ServiceImplUserMapper, User implements UserService { Override public PageUser pageByAge(Integer age, long current, long size) { LambdaQueryWrapperUser wrapper Wrappers.UserlambdaQuery() .eq(age ! null, User::getAge, age) .orderByDesc(User::getId); return this.page(Page.of(current, size), wrapper); } }4.3 測(cè)試基類把初始化收斂到一處不要在每一個(gè)測(cè)試類里重復(fù)寫initTableInfo抽一個(gè)基類出來(lái)public abstract class BaseMockTest { /** 全局共用一份避免每次 new 都往 GlobalConfigUtils 里加新 key */ private static final MybatisConfiguration CONFIGURATION new MybatisConfiguration(); private static final MapperBuilderAssistant ASSISTANT new MapperBuilderAssistant(CONFIGURATION, ); static { // 這個(gè)模塊里所有可能被 lambda 引用的實(shí)體集中在這里注冊(cè) TableInfoHelper.initTableInfo(ASSISTANT, User.class); TableInfoHelper.initTableInfo(ASSISTANT, Order.class); } }放在static塊里而不是BeforeEach好處有三個(gè)。第一每個(gè)測(cè)試類只初始化一次而不是每個(gè)用例一次第二static塊在類加載時(shí)執(zhí)行早于所有測(cè)試生命周期回調(diào)不會(huì)出現(xiàn)某個(gè)BeforeAll里先跑了別的邏輯的順序問(wèn)題第三JUnit 5 在并行執(zhí)行測(cè)試方法時(shí)static塊本身由 JVM 保證只執(zhí)行一次不存在并發(fā)寫緩存的問(wèn)題。如果你擔(dān)心后續(xù)新增實(shí)體忘了注冊(cè)可以寫一個(gè)自檢啟動(dòng)測(cè)試時(shí)掃一遍com.xxx.entity包下的所有類凡是帶TableName的如果TableInfoHelper.getTableInfo(clazz) null就直接拋異常。這個(gè)自檢我在一個(gè)三十多個(gè)實(shí)體的項(xiàng)目里加過(guò)成本不高收益是再也不會(huì)有新同事加了實(shí)體忘了注冊(cè)、然后一臉懵地來(lái)找我這種事了。實(shí)現(xiàn)思路可以用 Spring 的ClassPathScanningCandidateComponentProvider也可以簡(jiǎn)單地用 Reflections 庫(kù)。4.4 測(cè)試用例覆蓋三種典型斷言方式ExtendWith(MockitoExtension.class) class UserServiceImplTest extends BaseMockTest { Mock private UserMapper userMapper; InjectMocks private UserServiceImpl userService; Test DisplayName(分頁(yè)查詢mock 返回?cái)?shù)據(jù)斷言結(jié)果) void pageByAge_normal() { User u1 new User(); u1.setId(1L); u1.setUserName(張三); u1.setAge(20); PageUser mockPage Page.of(1, 10); mockPage.setRecords(Collections.singletonList(u1)); mockPage.setTotal(1L); when(userMapper.selectPage(any(), any())).thenReturn(mockPage); PageUser result userService.pageByAge(20, 1, 10); assertThat(result.getRecords()).hasSize(1); assertThat(result.getTotal()).isEqualTo(1L); } Test DisplayName(斷言 wrapper 的 SQL這條在修復(fù)前會(huì)報(bào) lambda cache) void pageByAge_checkSql() { when(userMapper.selectPage(any(), any())).thenReturn(Page.of(1, 10)); userService.pageByAge(20, 1, 10); ArgumentCaptorLambdaQueryWrapperUser captor ArgumentCaptor.forClass(LambdaQueryWrapper.class); verify(userMapper).selectPage(any(), captor.capture()); String sql captor.getValue().getTargetSql(); // 注意getTargetSql 會(huì)把 #{ew.paramNameValuePairs.MPGENVAL1} 替換成 ? assertThat(sql).contains(age).contains(ORDER BY id DESC); } Test DisplayName(參數(shù)為 null 時(shí)不拼接 age 條件) void pageByAge_nullAge() { when(userMapper.selectPage(any(), any())).thenReturn(Page.of(1, 10)); userService.pageByAge(null, 1, 10); ArgumentCaptorLambdaQueryWrapperUser captor ArgumentCaptor.forClass(LambdaQueryWrapper.class); verify(userMapper).selectPage(any(), captor.capture()); String sql captor.getValue().getTargetSql(); assertThat(sql).doesNotContain(age); } }第二個(gè)和第三個(gè)用例就是會(huì)報(bào)can not find lambda cache的典型寫法因?yàn)間etTargetSql()會(huì)真正去渲染 SQL 片段。加上基類的靜態(tài)初始化之后這兩個(gè)用例就能穩(wěn)定通過(guò)了。這里還有一個(gè)值得留意的細(xì)節(jié)getTargetSql()返回的 SQL 里參數(shù)占位符是?而不是#{ew.paramNameValuePairs.MPGENVAL1}。這是因?yàn)閃rapper接口里對(duì)getTargetSql的默認(rèn)實(shí)現(xiàn)做了正則替換。如果你需要斷言具體的參數(shù)值得去看getParamNameValuePairs()返回的 Map鍵是MPGENVAL1這種自動(dòng)生成的序號(hào)而不是屬性名。這個(gè)鍵名是 MyBatisPlus 內(nèi)部生成的寫斷言時(shí)不要去猜順序用getParamNameValuePairs().values()做集合斷言更穩(wěn)。另外一個(gè)容易忽略的點(diǎn)ExtendWith(MockitoExtension.class)默認(rèn)開啟嚴(yán)格打樁檢查。如果某個(gè)when(...)在測(cè)試?yán)餂]被用到會(huì)直接報(bào)UnnecessaryStubbingException讓測(cè)試失敗。上面前兩個(gè)用例里when用到了第三個(gè)也用到了都沒問(wèn)題。但如果你寫了一個(gè)只為兜底、實(shí)際沒觸發(fā)的when記得加lenient()或者改用Mockito.lenient().when(...)。4.5 mock 場(chǎng)景下分頁(yè)的坑和 500 條限制分頁(yè)這塊必須單獨(dú)說(shuō)因?yàn)樗驼鎸?shí)環(huán)境的行為差異很大很多人第一次寫會(huì)踩。userService.pageByAge(...)內(nèi)部調(diào)的是ServiceImpl#page(IPage, Wrapper)這個(gè)方法最終委托給baseMapper.selectPage(page, wrapper)。在真實(shí)環(huán)境里selectPage會(huì)被PaginationInnerInterceptor攔截自動(dòng)拼LIMIT、自動(dòng)執(zhí)行 count 查詢、把結(jié)果塞進(jìn)Page對(duì)象。但在 Mockito 單測(cè)里整個(gè)攔截器鏈都不存在selectPage是你自己打樁的返回什么就是什么。所以Page的records和total必須你自己設(shè)置否則斷言getTotal()時(shí)會(huì)拿到默認(rèn)值 0。Page的pages總頁(yè)數(shù)是在getPages()被調(diào)用時(shí)懶計(jì)算的依賴total和size只要total設(shè)對(duì)了就沒問(wèn)題。分頁(yè)參數(shù)校驗(yàn)比如 current 小于 1 時(shí)自動(dòng)糾正為 1是Page構(gòu)造器干的跟攔截器無(wú)關(guān)可以正常測(cè)試。至于熱詞里提到的單頁(yè) 500 條限制那來(lái)自PaginationInnerInterceptor的maxLimit配置典型寫法是Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); PaginationInnerInterceptor pagination new PaginationInnerInterceptor(DbType.MYSQL); // 單頁(yè)最多 500 條超出后按 overflow 策略處理 pagination.setMaxLimit(500L); // true超過(guò) maxLimit 時(shí)按 maxLimit 處理false超過(guò)時(shí)拋異常 pagination.setOverflow(false); interceptor.addInnerInterceptor(pagination); return interceptor; }這個(gè)限制在純 Mockito 單測(cè)里是驗(yàn)證不到的因?yàn)樵?mock 的selectPage被調(diào)用之前攔截器根本沒機(jī)會(huì)介入。如果你想在單測(cè)里覆蓋這個(gè)行為有兩條路一是切到MybatisPlusTest讓它進(jìn)真實(shí)的攔截器鏈二是單獨(dú)對(duì)PaginationInnerInterceptor寫一個(gè)測(cè)試手動(dòng)構(gòu)造Executor和MappedStatement調(diào)它的beforeQuery。后者寫起來(lái)很啰嗦需要 mock 掉Invocation、Executor、MappedStatement、BoundSql一堆對(duì)象我在一個(gè)對(duì)分頁(yè)安全要求很高的項(xiàng)目里寫過(guò)一次大概六十行代碼收益是能把前端傳 size100000 時(shí)后端是否真的截?cái)噙@條規(guī)則鎖死。如果你們的分頁(yè)確實(shí)是個(gè)風(fēng)險(xiǎn)點(diǎn)值得花這個(gè)成本。另外提一句IRepository。MyBatisPlus 3.5.4 之后引入了IRepositoryT和CrudRepositoryM, T寫法和IService不太一樣實(shí)體類型通過(guò)泛型解析而不是ServiceImpl的getSuperClassGenericType。這里有個(gè)坑千萬(wàn)不要用Mockito.mock(CrudRepository.class)去 mock 這類倉(cāng)儲(chǔ)接口Mockito 生成的動(dòng)態(tài)代理類會(huì)把泛型信息擦掉getEntityClass()拿回 null最終表現(xiàn)還是 lambda 緩存查不到。正確做法是用InjectMocks注入一個(gè)真實(shí)的實(shí)現(xiàn)類實(shí)例或者用Spy包一個(gè)真實(shí)實(shí)例。5. 排查速查表和幾個(gè)隱蔽的坑5.1 常見問(wèn)題速查報(bào)錯(cuò)或現(xiàn)象大概率原因處理辦法can not find lambda cache for this entity [X]測(cè)試環(huán)境沒初始化TableInfo基類靜態(tài)塊里調(diào)initTableInfo單跑綠、全量跑紅多 JVM fork緩存不共享或靜態(tài)狀態(tài)被污染每個(gè) JVM 自己初始化檢查靜態(tài)變量并行測(cè)試偶發(fā)失敗多個(gè)線程同時(shí)寫靜態(tài)緩存初始化放static塊或BeforeAll報(bào)錯(cuò)實(shí)體在生產(chǎn)環(huán)境從不報(bào)該實(shí)體沒有 Mapper從沒被注冊(cè)補(bǔ) Mapper或確認(rèn)是否該用 lambdanot found method writeReplace傳入的不是SFunction或方法引用來(lái)自非序列化接口檢查是否誤用了普通FunctionCannot call abstract real method對(duì)接口用了Spy換Mock或注入真實(shí)實(shí)現(xiàn)UnnecessaryStubbingException打了樁但沒用上刪掉多余樁或用lenient()getTargetSql里看不到具體參數(shù)值占位符被替換成?了改用getParamNameValuePairs()5.2 幾個(gè)不太容易被發(fā)現(xiàn)的坑坑一實(shí)體類里的TableField(exist false)字段不能用于 lambda 查詢。這個(gè)字段壓根不進(jìn)列名映射你寫wrapper.eq(User::getExtraInfo, x)屬性名extraInfo在緩存里查不到。不同版本的行為不一樣有的拋NPE、有的拋can not find column報(bào)錯(cuò)信息跟緩存問(wèn)題長(zhǎng)得像但根因不同。我一般建議 DTO 和實(shí)體徹底分開實(shí)體里不放展示字段??佣蘒njectMocks和Mock混用時(shí)Service 必須是真實(shí)實(shí)例。如果你的UserServiceImpl是通過(guò)Mockito.mock(UserServiceImpl.class)造出來(lái)的getEntityClass()反查泛型時(shí)會(huì)拿到 Mockito 生成的代理類泛型鏈斷了entityClass為 null。這時(shí)候tryInitCache里的兜底邏輯就失效了——它本來(lái)想用getEntityClass()的結(jié)果去覆蓋 lambda 自帶的類型結(jié)果兩邊都沒著落。所以務(wù)必用InjectMocks。坑三靜態(tài)工具類Db在單測(cè)里幾乎沒法用。com.baomidou.mybatisplus.extension.toolkit.Db提供了一批靜態(tài)查詢方法內(nèi)部通過(guò)SqlHelper拿SqlSessionFactory這個(gè) Factory 在純單測(cè)里是 null直接 NPE。如果你們的代碼里用了Db.lambdaQuery(...)要么把這段代碼抽到一個(gè)可注入的組件里要么這類方法只能用MybatisPlusTest覆蓋??铀腖ombok 的Accessors(chain true)會(huì)改變 getter 的形態(tài)嗎不會(huì)。Accessors(chain true)只影響 setter 的返回值類型getter 還是標(biāo)準(zhǔn)的getXxxPropertyNamer.methodToProperty能正常解析。但如果你用了Accessors(fluent true)getter 會(huì)變成userName()這種沒有g(shù)et前綴的形式methodToProperty的解析規(guī)則就不適用了lambda 查詢會(huì)得到錯(cuò)誤的屬性名。這個(gè)坑很隱蔽因?yàn)榫幾g期不報(bào)錯(cuò)只有跑到 SQL 渲染時(shí)才出問(wèn)題??游灏?SQL 打印在日志里本身就可能觸發(fā)這個(gè)異常。我見過(guò)一個(gè)切面在方法出口統(tǒng)一打印wrapper.getTargetSql()做審計(jì)日志。這個(gè)切面對(duì)所有方法生效包括單測(cè)。于是本來(lái)好好的單測(cè)因?yàn)檫@個(gè)切面被MockBean進(jìn)來(lái)或者切面用Component被掃到全部炸掉。排查這種問(wèn)題的方法是把堆棧里getTargetSql上方那幾幀看清楚是不是來(lái)自切面而不是測(cè)試代碼。5.3 怎么在 CI 上防止這個(gè)問(wèn)題回歸方案一上線之后最大的顧慮是以后新加的實(shí)體忘了注冊(cè)。我的處理是加兩個(gè)保險(xiǎn)。第一個(gè)保險(xiǎn)是前面說(shuō)的自檢在測(cè)試基類的static塊里掃一遍實(shí)體包凡是帶TableName但沒有TableInfo的直接拋異常并打印類名CI 會(huì)在第一個(gè)用例就紅比等到某個(gè)具體斷言失敗要快得多。第二個(gè)保險(xiǎn)是把基類做成強(qiáng)制的。在項(xiàng)目里加一條 ArchUnit 或者自定義的檢查規(guī)則*Test結(jié)尾的類必須繼承BaseMockTest或者在類上標(biāo)注一個(gè)自定義注解。這個(gè)規(guī)則可以用 ArchUnit 寫ArchTest static final ArchRule service_tests_should_extend_base classes() .that().haveSimpleNameEndingWith(ServiceImplTest) .should().beAssignableTo(BaseMockTest.class);這條規(guī)則的好處是把約定變成了編譯期/測(cè)試期的強(qiáng)制約束新人入職不用讀文檔也知道該怎么做。ArchUnit 的執(zhí)行開銷很小一般幾秒鐘塞進(jìn)單元測(cè)試階段完全沒問(wèn)題。另外還有一個(gè)習(xí)慣值得養(yǎng)成測(cè)試?yán)飻嘌?SQL 的時(shí)候優(yōu)先斷言結(jié)構(gòu)而不是完整字符串。assertThat(sql).contains(ORDER BY id DESC)比assertThat(sql).isEqualTo(SELECT ... FROM t_user WHERE ... ORDER BY id DESC)要穩(wěn)得多。后者在 MyBatisPlus 升級(jí)一小版本、列名排序變了、或者多了一個(gè)邏輯刪除條件之后就會(huì)紅維護(hù)成本極高。我見過(guò)一個(gè)項(xiàng)目因?yàn)閿嘌粤送暾?SQL升級(jí) 3.5.3 到 3.5.6 時(shí)改了四十多個(gè)測(cè)試類純粹是無(wú)效勞動(dòng)。最后再說(shuō)一個(gè)容易被忽略的工程習(xí)慣把TableInfoHelper.initTableInfo的調(diào)用集中在一個(gè)類里而不是散落在各個(gè)測(cè)試類中。集中之后將來(lái) MyBatisPlus 大版本升級(jí)導(dǎo)致 API 變了你只需要改一個(gè)文件。我上一家公司從 3.4.x 升到 3.5.x 的時(shí)候就是靠這一點(diǎn)把遷移成本壓到了半個(gè)小時(shí)以內(nèi)——三十多個(gè)測(cè)試類一行沒動(dòng)。我在實(shí)際做這套東西的時(shí)候最大的體會(huì)是單元測(cè)試?yán)镉龅降哪切┬W(xué)報(bào)錯(cuò)十有八九不是框架的問(wèn)題而是框架依賴的某個(gè)只在啟動(dòng)時(shí)做一次的準(zhǔn)備工作被測(cè)試環(huán)境跳過(guò)了。找到那個(gè)準(zhǔn)備工作把它顯式地補(bǔ)回去問(wèn)題就解決了。lambda 緩存是這樣DataSource初始化是這樣LocalDateTime的序列化器也是這樣。所以我現(xiàn)在的習(xí)慣是每接一個(gè)新的三方框架先去翻它的AutoConfiguration類看看啟動(dòng)階段到底做了哪些副作用這些副作用就是寫單測(cè)時(shí)必須手動(dòng)補(bǔ)齊的清單。
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
国产精品嫩草久久久久| 97色色色综合网站| 一区二区精品日韩欧美在线观看 | 久久久日本电影| 有码人妻系列| 久九九九九九九热| 97超碰jingpin| 国产激情av女片自拍| av网站免费看| 国内外激情在线| 97视频在线观看高清资源| 3p国产色噜噜一区| 国产久久av| 日韩日本欧美在线观看| 亚洲啪啪综合?v一区综合精品区| 亚春色色| 蜜桃久久一区| 黄色成年| 怡红院成人视频| 伊人久久蜜月| 欧美色图97| 99re在线视频国产| 国产美女91| 久久6热精品99视频| 欧亚乱色熟一区二区三四区| 九九久久一区二区三区| 91久久精品国产| 天天摸,夜夜摸| 人人透人人操| 综合色图,成人综合网| 日韩不卡毛片Av免费高清| 白丝被操91| 岛国网址国产| 日本一区二区成人在线| 福利视频一区二区微拍| 91精品伊人久久久大香线蕉91 | 白丝AV网站| 999久久久久久久精| 不卡码视频| 久久久久久久久久久久久久9999| 大香蕉宗合网在线| 69精品在线| 久久激情五月| 欧美极品女人的天堂| 国模少妇一区二区三区| 五月天婷婷综合| 可能人人看人人摸| 91黑人无码激情在线| 国产中文字幕曰本毛片| 日韩精品一区二区三区色欲| 日本有码久久| 伦在线97| 青操影院| 啪啪自拍九九综合| 欧美影院一区二区三区| 国产又色又粗又黄又爽| 久久99午夜精品一区人妻| 一级免费啪啪片| 久久婷婷五月天| 人妻天天爽夜夜爽精品2| av天天在线| 欧美综合色| 丰满人妻-区二区三区免费看| 亚洲黄色电影| 一级日本牲交大片好爽在线看| 亚洲精品第一| 久久久久久久久久久久久久9999| 欧美伦乱爱| 啊啊啊啊,啊啊好多水| 精品久9| 日本一级特级毛片视频| 少妇xx精品| 亚洲少妇喷视频看| 青青久日| 日韩不卡在线一区二区| 中文字幕精品专区搜索结果91| 欧美变态激情网| 亚洲精品国产熟女久久久| 国产精品久久久久久久久久久久久久吹 | 中文字幕乱碼在线| 9久9久9久9久视频网站| 91精品人妻一区二区三区蜜桃| 麻豆精品.欧美精品.日韩精品.| av网站国产主播在线| 欧美日韩一区二区三区四区蜜桃| 小草精彩毛片| 久久东京热久久| 国产精品无码在线| 久久成年精品| 国产在线能看的你懂的| 91色碰| 久久成人精品| 精品成人亚洲午夜电影| 久久本道| 婷婷激情四射| 日本99久久| 大香蕉伊人亚洲| 97在线观看视频| 永久免费发布性爱网| 美女露胸露屁股| 日韩电影免费网站麻豆视频| 亚洲一区二区三区不卡国产欧美| 91在线色| 欧美人人操人人插| 丰满人妻一区二区三区在线| 国产精品午夜AV完会免费| 丁香色五月 97干| 四虎免费看黄| 无码区蜜乳| 大香蕉十区| 日本不卡五区| 91爱综合| 五十路熟女人妻一区二区三区四区五| 狠狠色丁香| 亚洲第一页综合在线| 亚洲一卡2卡3卡4卡乱码网站 | 天美av在线| 天天操天天舔| 男同专区一区二区三区在线| 无码一区二区三区四区五区六区七区八区九区十区视频 | 久久偷拍人| 五十路熟女人妻一区二区在线观看| 两性综合网| 亚洲丨在线| 日本午夜久久电影| 福利视频一区二区微拍| 伊人久久大香线蕉亚洲五月天,青草青草欧美日本一区二区,欧美日产欧美日产国产 | 91九色丰满高潮| 久久久亚洲高清不打码| 97色涩| 永久免费发布性爱网| 涩涩久久精品| 国产精品亚洲免费| 97国产精品一区| 久久久久骚| 富女玩鸭子一级毛片| 蜜臀精品1区2区| 成人小说视频在线精品欧美| 97热视频在线观看| 天天干,夜夜爽| 国产9熟妇视频网站| 97最新在线播放视频| 97国产|免费| 亚洲影视综合网| 精品熟女呻吟久久91| 殴美牲| 涩综合导航| 欧美激情色婷婷花野真衣一区二区| 久久久久免费看少妇A片特黄| 丝袜狂射91| 99综合视频一体| 十八禁啪啪视频| 中文字幕免费观看| 婷婷久久大香蕉| 日韩无码一区二区三区| 91精品免费| 红杏大香蕉| 大香蕉www.超碰| 色狠狠一区二区三区香蕉| 97视频网站在线观看| 国产精品久久久久无码A√| 夜夜精品视频一区二区| 国产一区96在线| 日本精品网站在线中文| 久草加勒比一区在线| 黄网站黄视频网站进入口| 深夜激情无码| 亚州熟女乱伦| 东北老熟女| 丰满搜索结果 -第18页- 久久高清无码| 看日韩操逼| 91色色网站| 日本一级不卡一二区| 蜜桃久久一区二区三区| 免费精品福利在线观看| 国产怡红院| 中文字幕日韩人妻视频一区二区三区| 欧美亚洲中文| 东北女人高潮视频| 精品人妻伦一区二区三区久久| 青青爽| 殴美性色a级欧美| 啪啪资源网| 色图综合网| 香蕉精品二区二区| 一二三四区电影| 97公开久久| 久久侵犯人妻爽爽爽| 日本国产欧美高清在线| 久久首页| 手机午夜电影神马久久| 少妇久久久久久| 99久在线精品99re8| 久久久久ab| 亚洲视频一二区| 久无码| 日韩另类色图| 一区二区三区精品黑丝白丝酒店对鸡 | 亚洲偷拍自拍在线视频| 在线一道啪| 亚瑟国产精品久久无码| 国产精品不卡一区二区三区av| 好吊色青靑草| 91视频综合网| 蜜臀一区二区三区在线| 97碰| 亚洲欧洲无码bt精品合集| 国产400孕妇孕交群| 97亚洲精品超碰| 巨乳特殊服务按摩| 久久久久99999| 久久久性爱| 久久久青青草| 亚洲牲交| 国产亚洲精品A在线观看下载| 欧美999| 精品久久久av无码免费| 97在线精品观看视频| 欧美经典一区二区三区| 五月婷婷激情网| 色婷婷五月综合| 屌色在线97视频| 五月天婷婷色| 2025亚洲男人天堂| 欧美 亚洲 综合 制服 另类| 亚洲中文字幕久久无码精品| 中文字幕日韩电影人妻| 婷婷激情五月综合| 国产美女精品| 亚春色色| TS人妖另类精品视频系列| 最新亚洲黄色免费电影| 三级网色| 色女综合| 欧美日韩操操操| 在线观看中文av字幕| 久99热| 亚洲,欧美,春色,另类| 欧美18禁91| 少妇色综合| 青青五月天| 国产二区三区免费视频| 777奇米影视777四色| 久久最新免费视频23| 国产地址二三| AV麻豆免费一区| 久久久久国产精品片区无码直播| 中文字幕人妻丝袜| 亚洲高清在线se| 内射日韩大臀美女| 蜜臀在线看片| 国产高清成人免费视频| 在线播放一级无码视频| 久久熟女人| 天天看高清麻豆| 91色夜| 日本乱人伦片中文三区| 色婷婷狠狠| 超碰98综合网| 尤物av网站免费在线播放| 国产AV久久野战精品| 99久热| 美日韩在线不卡人妻| 蜜区区视频79 | 国产后入内射| 久久国产在线一区二区| 久久99视频| 久久一区,青青青青草视频在线播放| 久久久久九九九九九| 91丨国产丨白浆秘 洗澡动漫| 日本操BAV| 青青草日本中文字幕| 91熟女丨91老女人| 国内精品伊人久久久久影院会| 日本免费一区二| 久久久啊啊啊| 亚洲中文字母在线播放| 加勒比伊人综合| 老外又粗又长一晚做五次| 国产精品一二三免费网站| 超碰精品人妻狠狠干| 亚洲欧洲av影音| 久久精精区一区二区一蜜桃一区二区| 精品福利| 二对二中文字幕。| 78久久| 天天综合精品| 91爱啪| 婷婷六月天| 欧美 色 亚洲| 屁股久久久久久久久| 九九综合九九综合| 日han少妇无码| 国模无码人体一区二区三| 欧美午夜精品久久久久久超碰| 综合亚洲网| 中文字幕 国产 精品| 果冻传媒A片一二三区 | 碰人碰碰人人开房人肉| 久久一区二区高清免费| 中文字幕第23区| 人妻中文字幕日韩电影| 亚洲日韩资源| 久草婷婷| 久久超碰国产一区二区三区| 中文幕97| 5月婷婷6月六月丁香| 四虎免费在线播放| 碰碰在线视频| 高清在线不卡一区二区 视频| 久久97资源 网| 2024黄色视频| 国产日韩欧美| 97五月天| 大黄片做爱的大的| 高潮9999外国| 欧美少妇一区二区三区| 天天操天天干一区二区| 婷婷丁香人妻| 五月天色电影| 人人插人人搞人人操| 亚洲欧美洲综合| 天天天肏屄欧美| 成人八戒网站| 欧美天天综合网版| 东北女人的毛片| 日韩精品永久在线观看| 一区二区乱码福利| 大白逼三四级| 亚洲精品欧洲精品| 香蕉久久国产AV一区二区| 五月天亚洲色图| 欧美性爱一区二区三区四区 | 亚洲精品一卡二卡三卡福利视频网站 | 97国产精品国| 久久人人爽人人爽人人片Ⅴ| 91精品久久久久五月天精品| 超碰97人妻自拍| 日本一片一区| 亚洲激情网一二三四区| www.91理论| 啊啊嗯嗯好爽| 色哟哟精品1精品2| 欧美亚洲涩涩| 第四色亚洲色图| 丁香九月激情| 国产人伦a片信息免费片| 91老司机精品| 4tube欧美女厕所| 国产熟女一区二区丰满| 小少妇| 午夜无码精品免费看性色| 极品国产内射| 72av视频| 一区二区三区四区免费视频| 欧美色亚洲| 久草综合网| 少妇内射视频| 日韩精品操少妇| 中文字幕一区 二 区 三 四 五 区日 日 骚 | 99精品无码| 天堂精品小草| 性生活久久久久久久久久| 亚洲综合五月天| 一级久久久久久久久久久| 欧美一区二区福利在线| 1000部熟女视频在线观看| 亚洲色交| 欧美综合网在线| 淫纸中9区| 凹凸 69堂 在线播放| 日本不卡一区二区三区| 91丨精品丨国产丨丝袜| 热久日综合| 2019AV天堂| 97 国产一区| 啊嗯好大视频在线观看| 日韩欧美成人大香蕉| 五月天激情小说| 99无码精品| 丁香久久| 北条麻妃99精品青青久久| 六月丁香五月婷婷| 亚洲日本成人动漫| 天天操天天射青青草| 日韩三级一区| 麻豆久久久久久久久丝袜| 欧美亚综合色图| 超碰1024久久| 国产精品久久久999| 久久人妻无码毛片A片麻豆| 久久草视频污视频| 精品免费成人久久| v91av| 乱性AV| 久久69精品久久久久久久| 岛国视频一二三区| 操99| 人妻出轨一区二区三区| 国产成人+综合亚洲+天堂| 午夜人妻精品综合在线| 亚洲天堂电影精品一区| 97色诱| 91n免费处女| 免费99精品国产自在在线| 亚洲欧美激情小说| 麻豆天美传媒毛片| 久操com| 久久ww| 高清不卡一二三区视频......| 夜夜操天天肏| 96国产精品| 91在线欧美| 最新亚洲人成网站在线影院| 熟女人妻一区二区三区| 九一屌逼| 超碰在线1234区| 手机在线中文字幕国产| 免费黄色片子| 亚洲中文字幕日产无码久久| 亚洲人人夜夜澡人人爽| 欧美色999| 老熟女乱子伦中文字幕一区二区| 日本女人操逼| 亚洲欧洲日产国产综合网| 91中文字幕在线观看| 日本一区二区中文字幕久久| 久久肏大逼| 麻豆久久久久久久久丝袜| 日韩 女同 综合| 91老熟女| 五月丁香六月激情| 加勒比人妻综合| 后入式免费视频| 2018天天干在线视频| 色播五月婷婷| 中文字幕、久久精品国产2020、久久综合久久自在自线精品自、亚洲 | 超碰 另类 欧美 | 男女香蕉一区二区| 岛国在线国产| 校园春色 男人天堂| 国产在线精品电影观看| 秋霞午夜成人福利片片| 99在线精品观看99| 97K超碰在线| 伊人久久综合影院| 99操| 免费AV中文网在线观看| 激情五月综合| 中国91AV| 九九无码视频| 亚洲91综合| 亚洲色图欧美色图日韩色图| AV高清一区| 校园春色亚洲| 天天舔天天 | 婷婷午夜成人色中色| 成人AV素股で擦久久| 黄页| 亚洲色鬼| 精品国产乱码久久久久久网站入口| 欧亚免费视频| 校园春色美腿丝袜 | 日本 色 导航| 日韩av色图| 欧美的性爱网站免费| 干B视频伊人网| 青娱乐淫乱1314| 九一亚洲国产免费| 综合伊人激情| 超碰538| 人人摸.人人色| 欧美成人综合| 免费看黄视频亚洲网站| 中文字幕视频免费| 日韩欧美国产高清视频| 精品国产丝袜一区二区三区乱码| 精品国产一区二区三区久久久蜜臀 | 亚洲性爱免费电影| 蜜桃网熟妇| 色综合久| 欧美视频一| 日韩精品99久久久久久中文字幕 | 香蕉在线一区二区三区| 久久久亚洲熟妇熟女| 久久人妻四季| 国产精品一区二区校花| 超碰 国产熟女精品一区| 精品一区二区亚洲国产| 久操97| 亚洲欧美setu| 色色色色网站| 天天日天天干天天操| 国产91精品久久久久久久网曝门| 人妻少妇被猛烈进入中| 羞答答AV中文字| 亚洲老熟妇xxx| 日本性感人妻91| 国产乱码精品久久久久久| 国产真实野战在线视频| 夜夜欢天天干| 欧美黑人极品高潮喷吹熟女黑人性暴力日韩在线欧美极品一区二区老师 | avav青青草久久夜| 伊人色综合超碰| 久草网站免费在线观看| 人妻丝袜美腿中文字幕| 大香蕉啪啪啪啪在线| 亚洲乱熟女一区二区三区大香蕉| 午夜超碰| 国产后入清纯| 蜜桃臀 后入 一区 二区 三区 在线| 欧美一区二区福利在线| 欧美成人精品欧美一级乱黄一区二…| 另类亚洲图色| 性爱综合网| 国产精品亚洲天堂网址| 国产精品96| AV色图| 亚洲熟女乱色| 欧美男人一区| 天天躁日日躁XXXXYY| 成 人 A V免费视频在线观看| 日产成人久久| 欧美后入视频| 中文字幕在线观看第二页| 破苞ⅩXXX性无码动漫无码| 日韩免费簧片| 好爽视频在线观看视频| 黑丝制服中文字幕| 国产欧美成人精品| 久草资源在线视频官方总站日韩丝袜美腿| 久久久五月天| 国产97色在线| 婷婷五月天激情网| 欧美日韩亚洲一区二区在线观看| 一区二区高清视频| 日本二三四区| 欧美美女视频| 91美女视频。| 自拍第一页| 日韩色女精品| 呦女网站| 97视频在线视频| 久久人爽| 97一本大道亚洲一区| 亚洲色图加勒比| 欧美少妇熟女| 999在线电影香蕉| 26uuu欧美| 探花激情视频| 91丨九色丨43老版熟女| 欧美日韩第一页| 色丁香久久| 国产高清成人传媒影视| 人人射人人操人人摸| 国产毛片在线| 日韩欧美综合激情| 激情综合二| 亚洲一欧洲中文字幕在线| 国产女人和拘做爰视频| 91快色色色色色| 亚洲国产午夜真人一级片中文字幕精品黄网站 | 欧亚性爱啪啪| 国产呦精品一区二区三区下载| 亚洲综合精品国产一区| 强奸a片网| www.久久| 一二三啪啪专区| 中文久久一区| 囯产精品强| 久久九九久精品国产尤物|国产精品爽黄69天堂A片潘金莲,国产亚洲精品第一综合 | 97一区二区蜜臀| 第45页一区二区| 天天插夜夜爽| 精品大全99999| 国产免费内射视频| 欧美人人曰人人操人人射射| 成人三一级一片aaa| 无色无码| 亚洲综合色男人网| 老女人碰碰在线碰碰视频| 色五月激情AV在线| 酒色综合网| 免费看黄片现成| 国产精品制服丝袜清纯唯美| 丁香五月av| 日韩一区二区熟女| 国产自偷| 久久无码一区二区二三区性色| 自拍视频一区在线观看| 色色五月天婷婷| 亚洲五区熟女| 大香蕉日韩| 日本高清视频xxxx| 久99热| 久久少妇视频| 精品日日人妻| 日韩欧美tv一区二区在线观看| 午夜精品视频777| 四虎AV无码| 欧美后入式| 青娱乐999| 免費黃色視頻觀看一| yazhousetuoumei| 久久r精品| 麻豆国产97在线| 无码自拍SM| 麻豆精品天美| 一起草三级AV电影在线观看| 欧美刺激色黄片免费看| 性色av一区二区| 999精品久久久久久久| 岛国片国产成人亚洲播放| 久久超碰爱| 精品久久久一本一道| 日韩免费高清大片在线| 欧美后进式| 97在线视频观看免费| WWW操逼| 水澄无码AV| 国产精品69久久久久久久| 亚洲免费成人在线高清无码视频 | 免费国产视频| 精品久热| 综合网亚洲1| 国产精品一区av在线| ss久久| 国产60页| 夜夜操二区| 亚洲高清欧美总合| 国产女人成人精品视频| 日本五区不卡| 欧美性爱视频免费一区一A | 在线观看精品国产免费| 久久亚洲色图中文字幕| av一区二区三区四区| 欧美性暴力猛交XXXX| 超清中文乱码字幕| 久久天天摸| 啊啊啊好想要| 丁香五月天婷婷姐| 国产一级高清免费观看| 天天添天天干电影| 麻豆久久精品亚洲精品88 | 97在线免费观看| 99久久综合| 另类欧美色| 天天看综合网| 97无码视频在线播放| 亚洲成人一二三区| 妇女性内射冈站HDWWWCOM| 九九热五区| 18禁中文字幕| 久久亚洲天堂| 国产激情综合五月久久| 香蕉视频欧美一卡二卡| 欧美男女午夜啪啪| 操逼日批| 91精品人妻五十路| 九九热超碰| 试看60秒 爽| 久久超碰亚洲人| 在线A日本| 熟妇一区,二区,三区。| 1024人妻| 在线毛片片免费观看| 亚州色图欧美| 成人三级片无码| 中文字幕乱码在线观看| 免费人人搞97| 黄色视频特级毛片| 女色综合| 97在线观视频免费观看| 综合久久中文字幕综合日韩精品| 亚洲色人阁| 久草婷婷| 97色婷| 色欲久久久久综合网| 亚洲性猛| 亚洲欧美一区二区三区在钱蜜桃| 永久免费av无码网站国产app| 亚州日韩97| 婷婷五月天补不补| A 在线网址| 青青操在线视频| 加勒比综合九九99视频在线播放| 欧美亚洲另类在线蜜桃| 91天美| 91精品人妻啪啪间| 麻豆视频test| 人人操人人摸人| 熟妇综合一区二区三区| 乱色老一区二区三区的观看方式| 日本天天吊| 国产成人免费观看在线视频| 人妻天天爽天天爽三区| AV久日| 亚洲码和欧洲精品激情系列| 色5月婷婷| 男人天堂黄片| 女性91网站| 色婷婷日韩精品一区二区三区| 天天看片天天爽| 国产AV久久久蜜爱影集| 熟女乱伦A| 亚洲伊人成综合成人网| 久久久久久久久女黄| 久久久久九九九九九| 搡老女人老91妇女老熟女| 亚洲天堂人人妻| 国产精品对白自产拍| 国产性刺激| www五月| 国产av强奸美女| 欧美黑人极品高潮喷吹熟女黑人性暴力日韩在线欧美极品一区二区老师黑人潮喷一 | 99热精品在线观看| 五月天玖玖资源站| 都市久久精品激情亚洲| 97色碰| 久久人妻熟女一区二区| 性色高清..……| 欧美午夜视频| 免费人人搞97| 精品人妻一区二区免费蜜桃| 亚洲18禁| 97久久精品亚洲| 五月天激情小说网| 在线播放中文字幕| 久9热| 欧美成人一区二区三区在线播放| 国产精品嫩草久久久久| 成人一级性爱| 国产91啪| 少妇高潮对白在线观看| 视频国产精品未满十八禁止在线观看| 国产亚洲精品A在线观看下载| 亚洲情色综合| 张柏芝国产一区在线观看| 综合网91| 亚洲欧美另类激情小说| 国产一级高清免费观看| 国产精品直播在线观看直播| 伊人热综合| 激情黄色片在线观看| 91久久免费视频互動交流| 干我久操| 制度丝袜99| 人人摸人人干人人拍97| 国产熟女乱论| 色婷婷导航| 美女刺激久久国产欧美| 麻豆2区1区天美| 欧美性爱一内片一区二区三区| 国产精品乱人伊人网| 成人A片男人的天堂| 怡红院成人av| 久久精品99| 久9爱精品| 欧美精品宗合| 99这里只有精品国产| 精品国产丝袜一区二区三区乱码 | 骚日日av| 在线中文字幕视频| 強姦亂倫a| 围产精品一区二区三区视频播放| 蜜乳AV色欲AVAV无码| 五月丁香综合网| 中文字幕av久久爽Av| 青青三级视频| 农村妇女精品一二区| CCYY草草影院地址入口| 国产高清MV操逼视频| 人人摸人人干| 天天做天天爱天天爽AV| 久久久久久无码人妻中文字幕| 午夜男人的天堂| 久久黄片国产一区二区| 日本黄 R色 成 人网站| 婷婷成人久久久精品| 亚州欧美总和| 欧美色999| 婷婷视频在线免费观看| 亚洲色鬼| 好一吊区二区| 99视频这有这里有精品| 最新av在线| 熟女少妇一区二区三区| 97超碰磁| 欧洲色色| 99精品人人爽| 日本孕妇一区二区视频操逼免费看 | 精品人妻一区二区乱码一区二区| 欧美色老汉| 大香蕉黄色一级片免费看| 欧美后进式| 99国产精品自在自在| 91香蕉国产尤物视频| 成人午夜视频免费播放| 四虎免费看黄| 男人天堂电影院| 久操精品网| 亚洲色情在线影视| 999久久久免费精品国产牛牛| 欧美丰满熟妇XXXX性ppX人交| 亚洲av热热色| 粉嫩av在线| 婷婷91| 91亚洲丝袜| 中文字幕久热视频在线| 欧美性战999| 精品传媒在线一区| 久久精品色欧美aⅴ一区二区| 99国产精品久久久久久久成人热| 日韩色| 99热在线观看| 国产精品69久久久久久久| 国产中文大片资源中文字幕| 97蜜桃综合| 亚洲黑人在线| 久久久久久久一级黄色打同平台| 熟女高潮精品一区二区| 亚洲最大的综合性av| 97这里只精品| 午夜无遮挡男女啪啪视频| 亚洲情色一区综合| 秋霞一集毛片观看| 少妇国产不卡| 欧美片第一页| 欧美色图偷拍另类| 内射夫妻三片| 综合网欧| 国产日韩区| 九九国产热| 国产久久av| 99这里都是精品| 亚洲少妇中文字幕网址| 999久久芭蕾| 久久五月天婷婷| 欧洲亚洲人妻无码高清久久三区四区| 免费看欧美美女黄色大片 | 在线 制服丝袜中出 人妻| 91美女视频。| 少妇二级| 国产一区二区成人av在线播放| 禁十八久久| 日韩操逼HD| 日韩成人人妻网站| 99热最新| 亚洲情色欧美| 日韩午夜国产| Blackedraw视频一区二区| 亚州五月| 国产伦精品免编号公布| 性爱视频免费网址| 欧美日本不卡| 大香蕉92| 91精品大奶人妻| 好吊色青靑草| 鸥美插入视频| 色官网在线| 成人怡红院| 欧美日动态视频| 新版天堂中文资源8在线| 久久精品超碰| 上床不卡网站| 亚洲综合一区二区| 91操熟女| 久久久一区二区| 五月激情影院| 人人玩人人添人人澡免费| 91精品久久久久久77777| 人妻熟女午夜精品在线| {男男暴菊gay无套网站| 中文无线日韩一区| 色一射色一射| aaaa黄片| 四虎国产精品永久在线囯在线| 老司机免费视频在线91| 国内外色色色色色成人视频| 国产成人99久久亚洲综合| 久久精品男人的天堂| 中文字幕日产av人| 玖玖玖玖精品国产剧情| 国产免费黄色一级大片| 啊啊啊啊啊舒服| 久久久久久久久久久97| 亚洲一区二区中文字幕| 欧美狠狠干| 欧日韩一二三f区| 日韩成人午夜精品久久高潮| 色五月综合| 中文字幕一区二区日韩网| 午夜传煤十二区精品| 青青草字幕AV| 艳美熟妇先锋一二三区| www欧美性爱| 少妇厨房愉情理伦片bd在线观看| 欧美综合天堂| julia ann久久| 啊灬快c我灬啊灬用力灬啊灬-国产精品性做久久久久久-成人AV | 97干在线| 色与欲影视天天看综合网| 99www.bibizy香蕉资源国产一区二区三区高清 | 99re69综合| 黄色网址久久精品欧美喷水| 亚洲av淫乱| 18啪啪手机免费性爱| 欧美性色网| 91精品国| 少妇特黄一区二区三区| 青青国产在线拍揄自揄拍| 东北夫妻性偷拍| 久久婷婷色| 操逼网免费无码视频| www.伪伪| 欧美日韩国产另类综合| 一级片视频啪啪| 1240青青草一区二区三区视频天爱| 黑人综合色| 97超碰超欧美。| 农村妇女精品一区二区| yazhousetuoumei| 97蜜桃综合| 日韩AV一区二区三区四四| 国产久久久久久久久一区二区| 国产亚洲精品农村妇女| 第四色奇米影视777| 黄色免费网| 激情综合网亚洲| 加勒比综合网| 欧美天天| 欧美夜夜草视频| 久9re热视频这里只有精品| 极品白嫩美少妇在地板上位骑射淫水泛滥| 男人的天堂Va| 可乐操亚洲蜜911| 99草精| 国产日韩美女小穴视频网站不卡| 91热色| 美女好片色日本| 欧美亚洲在线| 欧美色图综合网| 操逼操逼操| 丰满美女一级毛片在线播放| 蜜乳AV免费观看| 国内精品久久人妻性色av| 亚洲啪啪视频免费| 日韩国产不卡在线视频| 一区二区三区四区免费视频| 国产Aα| 日韩中文字幕二区| www.狠狠| 欧洲精品一二三在线| 天操天操夜操夜月操月年年操操| 男人的天堂三级| 亚州欧美另类| 亚洲中文字幕熟女| 国产一区二区三三视频| 欧美亚洲日本视频久久久| 久久婷婷亚洲| 91超碰人人| 亚洲色图欧美另类在线| 欧美精品欧美精品系列| 999久久久九九九九| 在线视频 亚洲精品| 又大又长又粗又爽又黄| 黄aaaaaaaaaaaaaaaaaa色网站| 综合久久婷婷| 日韩中文字幕熟妇人妻| 综合九九| 91熟女丨91老女人| 收看日本人日bb| 97人人模人人爽人人| 少妇免费视频| 小草av不卡亚洲二区| 久久粉色| 无码天天操| 青青草日韩无码| 色综和网| www国产精品| 小视频玖玖| 天天射,天天操,天天爽-国内精品一区二区三区-成人AV | 一本久久精品中文字| 精人妻一区二区三区| 美日韩男女操屄视频| 无码国产精品午夜不卡(| 嗯嗯,啊啊,国产精品| 老鸭窝日丰县女人| 国产精品高潮久久久无码| 久久AV无码网址| 少妇被玩视频二三区| 哑洲在线| 日本高清视频xxxx| 丝袜美腿诱惑亚洲欧美视频在线观看| 国产青视频| 日韩九九九| 日韩免费看黄片| www.99热在线只有精品| 日夜精品| 女人喷水视频在线观看| 男人干美女| 999999精品| 91狼人| 色天欧美| 日韩中文字幕国产| 射 色综合| 67914在线兔费成人视频| 国内偷自视频区视频综合| 91狠| 亚洲深夜福利| 在线人人人人人人精品超| 爽爽爽免费视频| 人妻三级在线中文字幕| 91超级碰| 中日韩久久久免费看| 嗯啊抽插大香蕉网页| 丁香婷婷激情五月天无毒不卡| 五十路熟女人妻一区二区在线观看 | 日本新免费二区三区| 在线毛片片免费观看| 亚洲图片欧美91N| 男女啊啊啊啊啊| 婷婷操逼| 久久精品操| 欧美十八禁在线看| 大香蕉日韩欧美| 午夜精品久久久久久久99蜜桃一| 亚洲成人妻日韩在线| 高潮毛片无遮挡高清免费| 欧中日成人免费影视| 熟女探花啪啪| 99热这里只有精| 在线亚洲欧美| 炮色五月| 黄片视频观看| 97色诱| {男男暴菊gay无套网站| 久久久久久九九九九-美女久久久久久久-成人AV| 国产剧情在线| 区日韩亚洲乱码av电影| 亚洲综合九九| 日日天天久久啊啊aaa| 亚洲成a人v欧美综合天堂下载| 欧美综合骚| 国产在线观看一区二区三区| 国产精品乱码久久久久久久久久久久| 激情综合网激情综合| 熟女色图在线| 亚洲欧洲综合成人av一区| 97超碰精品成| 插欧洲美女欧美精品| 天天欲望网| 超碰亚洲欧美日韩无| 色综合国产在线观看| 91l欧美在线| 一级黄色牲爱A级片| 97国产精品在线观看| 亚洲 日韩 欧美 国产综合体| 中文字幕99999| 婷婷五月天久久精品视频一区二区三区 | 日本欧美亚洲高清在线看| 黄站在线免费观看| 伊人影院中文字幕| 国产精品一区二区亚洲人成毛片| 91丝袜在线视频| 国内毛片无码一级毛片| 日本天天干天天操一区| 青青草吊丝| 色成人Www精品永久观看| 欧美色97| 麻豆久久久久久久久丝袜| 久久久久久日韩| 色吊丝 日日骚 清纯唯美| 久久久久久性爱视频| 啪啪资源网| 亚洲天天更新| 超碰中文字幕人妻草一区| 日韩黄色电影网站| 中文视频在线观看| AV中文字幕剧情1区2区3| 婷婷亚洲色| 天天激情综合站| 91精品国产91熟女| 嫩草伊人久久精品| 免费一级视频特黄色大片| 欧洲在线性爱视频| 中日992视频| 欧美亚综合色图| 动漫爆乳3D奶水一区在线观看| 国产强奸乱伦无码视频| 久久久少妇诱惑精品视频| 日本淫色网| 大地资源在线观看中文第二页| 人妻色偷色噜| 久久久免费高清中文视频| 美女裸体麻豆天美蜜桃91| 国产无马av| 中文字幕乱在线伦视频中文字幕乱码在线| 校园春色 亚洲| 操亚州| 亚洲精品久久久久久久久豆丁网| 熟女精品va中文字幕| 欧美片第一页| 91无码人妻精品一区二区三区蜜桃| 中文有码第五页| 99色视频| 国模吧 一区二区三区| 欧美五十路熟| 国产女大学生AV| 91无码人妻精品一区二区三区蜜桃| 神马久久久久久久久久| 天天操狠狠日夜夜干超碰撸com视频在线观看 | 人人操我人人干| 日韩无码一区二区三区| 成人开心网在线视频| 国产青青美女玩逼视频| 国产美脚女优尤物在线观看| 香蕉久久国产AV一区二区| 午夜福利免费精品视频| 少妇一区二区三区精选| 精品无码欧美三级| 欧美性色网| 久久久无码精品人妻二区| 中国的操老妇女| 秋霞午夜视频一区二区| 日韩久久超碰色| 丝袜夫妻自拍| 天综合网| 荡小穴在线观看| 日韩有码免费视频| 蜜臀一区二区三区在线| 色爱国产| 婷婷丁香五月天综合东京热| 五十路六十路七十路熟婆| 久久久久亚洲| 青青在线视频日韩欧美| 麻豆精品.欧美精品.日韩精品.| 亚洲色棕合| 白嫩妹子国产骚| 欧美第五页| 亚洲色欧| 巨乳特殊服务按摩| 精品国产乱子伦一区二区三区,精品一| 91激情国产| 日本2020一区二区| 久久亚洲一区二区色婷婷| 欧美精品系列| 综合五月天| 2017天天操| 好爽视频在线观看视频| 免费视频一二三区| 亚洲色图欧美一区二区不卡| 探花精品 一区二区| 午夜成人爽爽爽爽A片李冰冰| 日本潮催一卡操| 人人干黄色| 亚洲天堂人妻熟妇视频| 亚洲图片欧洲图片aⅴ| 国产粉嫩出水在线播放| 涩五月婷婷|