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

深入探究 MyBatis 緩存機制

開發
本文我們將一同踏上探索 MyBatis 緩存的奇妙之旅,我們將逐步揭開它神秘的面紗,深入剖析其背后的原理、結構和運作方式。

在當今的軟件開發領域,性能優化始終是一個備受關注的核心議題。而在眾多提升性能的技術手段中,MyBatis 緩存無疑占據著重要的一席之地。當我們深入探索 MyBatis 的世界時,會發現其緩存機制宛如一座隱藏的寶藏,蘊含著巨大的潛力和價值。

在接下來的篇章中,我們將一同踏上探索 MyBatis 緩存的奇妙之旅。我們將逐步揭開它神秘的面紗,深入剖析其背后的原理、結構和運作方式。通過了解它是如何巧妙地減少數據庫查詢次數、提升系統響應速度,我們能更好地把握這一強大工具,為我們的開發項目帶來更卓越的性能表現。

一、詳解一級緩存

1. 什么是一級緩存

當我們建立SqlSession時,就可以通過Mybatis進行sql查詢,假如本次session查詢時我們需要進行兩次相同的sql查詢,就需要進行進行兩次的磁盤IO,為了避免這種沒必要的等待,Mybatis為每一個SqlSession設置一級緩存,在同一個SqlSession中,一級緩存會將第一次查詢結果緩存起來,第二次相同的查詢就可以直接使用了。

2. 一級緩存使用示例

Mybatis默認是開啟一級緩存的,如下所示,可以發現只要第二次使用的sql和參數一樣,就會從一級緩存中獲取數據。

 User1 user1 = user1Mapper.select("1");
        logger.info("一級緩存第一次查詢:[{}]", user1);

        User1 user11 = user1Mapper.select("1");
        logger.info("一級緩存第二次查詢:[{}]", user11);


        User1 user12 = user1Mapper.select("2");
        logger.info("一級緩存第三次查詢,id不同:[{}]", user12);

輸出結果:

2022-11-27 15:51:28,313 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==>  Preparing: select * from user1 where id = ?
2022-11-27 15:51:28,338 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==> Parameters: 1(String)
2022-11-27 15:51:28,539 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - <==      Total: 1
2022-11-27 15:51:28,541 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==>  Preparing: select * from user1 where id = ?
 2022-11-27 15:51:28,541 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==> Parameters: 2(String)
[main] INFO com.sharkchili.mapper.MyBatisTest - 一級緩存第一次查詢:[User1{id='1', name='小明', user2=null}]



[main] INFO com.sharkchili.mapper.MyBatisTest - 一級緩存第二次查詢:[User1{id='1', name='小明', user2=null}]
 2022-11-27 15:51:28,667 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - <==      Total: 1
[main] INFO com.sharkchili.mapper.MyBatisTest - 一級緩存第三次查詢,id不同:[User1{id='2', name='小王', user2=null}]    

3. 一級緩存的執行過程

當然我們也得有一個查詢代碼,查詢代碼如下所示:

 User1 user1 = user1Mapper.select("1");
        logger.info("一級緩存第一次查詢:[{}]", user1);

本質上mapper代理對象進行查詢操作時底層的BaseExecutor會調用queryFromDatabase獲取查詢結果,然后將查詢結果存到緩存中:

private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

        List list;
        try {
        //執行并獲取查詢結果
            list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
            this.localCache.removeObject(key);
        }

  //基于本次查詢用到的MappedStatement , 參數, rowBounds, sql作為key將結果緩存
        this.localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
            this.localOutputParameterCache.putObject(key, parameter);
        }

        return list;
    }

總結一下流程就如下圖所示:

4. 一級緩存的生命周期

  • 當SqlSession調用了close之后,會直接釋放PerpetualCache對象,緩存自然不能使用了。
  • 進行update、delete、insert等操作,緩存就會被清空,但是緩存對象還能用。
  • 調用clearCache同理,緩存被清空,但是對象還能用。

二、詳解二級緩存

1. 什么是二級緩存

二級緩存是mybatis為了解決跨session緩存數據所增加的一層面向namespace級別的緩存方案,即以mapper文件為單位劃分的緩存空間,通過開啟二級緩存,程序執行查詢時會優先從全局共享的的二級緩存開始查詢,如果全局的二級緩存沒有數據,再通過一級緩存查詢,如果有則返回并返回,如果沒有則執行SQL查詢依次緩存到一級緩存、二級緩存中:

2. 二級緩存使用示例

為了討論二級緩存,我們不妨展示一個簡單的二級緩存配置示例,首先Mybatis配置開啟二級緩存,其實這個可以不用配置,默認的情況下是true:

 <settings>
    
        <!--開啟二級緩存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>

對應的Mapper文件下添加下面這段配置:

    <cache/>

然后我們給出對的測試代碼:

   UserMapper userMapper = SpringUtil.getBean(UserMapper.class);
        User user = new User();
        user.setId(1L);
        //第一次查詢
        User u = userMapper.selectByUserId(user);
        log.info("user:{}", JSONUtil.toJsonStr(u));
        //第二次查詢
        User u2 = userMapper.selectByUserId(user);
        log.info("user:{}", JSONUtil.toJsonStr(u2));

可以看到使用同樣的會話,第二次查詢不會查詢SQL而是直接從二級緩存獲取數據:

2024-12-13 12:13:00.458  INFO 17996 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2024-12-13 12:13:00.464 DEBUG 17996 --- [           main] c.s.mapper.UserMapper.selectByUserId     : ==>  Preparing: select u.id id, u.name name , m.total total from user u inner join money m on u.id = m.u_id where u.id = 1
2024-12-13 12:13:00.482 DEBUG 17996 --- [           main] c.s.mapper.UserMapper.selectByUserId     : ==> Parameters: 
2024-12-13 12:13:00.498 DEBUG 17996 --- [           main] c.s.mapper.UserMapper.selectByUserId     : <==      Total: 1
2024-12-13 12:13:00.549  INFO 17996 --- [           main] com.sharkChili.WebApplication            : user:{"id":1,"name":"xiaoming","total":50}



2024-12-13 12:13:00.550 DEBUG 17996 --- [           main] com.sharkChili.mapper.UserMapper         : Cache Hit Ratio [com.sharkChili.mapper.UserMapper]: 0.5
2024-12-13 12:13:00.550  INFO 17996 --- [           main] com.sharkChili.WebApplication            : user:{"id":1,"name":"xiaoming","total":50}

3. 二級緩存的工作模式

在開啟二級緩存配置后,框架會首先去CachingExecutor看看是否有緩存數據,若沒有則會從一級緩存查詢,實在找不到就通過BaseExecutor查詢并處理完緩存起來。

注意這里CachingExecutor用到了裝飾者模式,將Executor 組合進來,所以CachingExecutor會先調用(List)this.tcm.getObject(cache, key);看看緩存中是否有數據,若沒有在進行進一步查詢并緩存的操作。

//將基礎執行器作為被裝飾的成員屬性組合進來
 private final Executor delegate;

public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
        Cache cache = ms.getCache();
        if (cache != null) {
            this.flushCacheIfRequired(ms);
            //開啟二級緩存則執行該邏輯
            if (ms.isUseCache() && resultHandler == null) {
                this.ensureNoOutParams(ms, boundSql);
                //先去緩存查詢
                List<E> list = (List)this.tcm.getObject(cache, key);
                if (list == null) {
                // 若為空則調用BaseExecutor 進行數據獲取
                    list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
                    //將數據存到二級緩存中
                    this.tcm.putObject(cache, key, list);
                }

                return list;
            }
        }
  //調用BaseExecutor 獲取查詢結果并緩存
        return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }

4. 二級緩存怎么作用域

二級緩存怎么作用域有兩種:

  • 自定義劃分,我們在每個Mapper.xml中添加 <cache/>使得每一個mapper都有一個全局的獨立緩存空間:

  • 假如我們希望多個mapper共享一個空間的話,需要被分享的mapper使用<cache/>,而其他mapper則用<cache-ref namespace="">指向這個空間即可。

5. 使用二級緩存要具備的幾個條件

總的來說是三個條件:

  • 全局配置開啟二級緩存:<setting name="cacheEnabled" value="true"/>,默認是true的。
  • mapper.xml標簽配置了 <cache/>或者 <cache-ref/>
  • select語句配置useCache=true

6. 二級緩存實現的選擇有哪些和默認項

有三種吧:

  • 框架自身提供了很多緩存方案,這些緩存還提供了不同的回收策略:例如LRU、FIFO等。
  • 用戶繼承接口org.apache.ibatis.cache.Cache自行實現一個緩存。
  • 通過第三方緩存工具集成。

對于Mybatis的二級緩存默認緩存算法,如下圖,可以看到框架自身基于裝飾者模式實現了很多緩存工具,并且每個緩存容量都有限制,不同的緩存工具內存回收策略是不同的:例如LruCache即最近最少使用算法,內存容量滿了就回收到現在為止最不常用的。而FifoCache同理,內存滿了之后回收最先被緩存的數據,ScheduledCache則是定時清理緩存了。

7. 二級緩存關聯刷新問題

我們直接從一個比較實際的場景出發,首先我們有一張user表,里面有一條id為1的用戶數據,name是xiaoming,然后有一張關聯表money,它記錄xiaoming的錢包金額為50,對應數據信息如下:

-- SELECT * FROM  `user` u ;

id|name    |
--+--------+
 1|xiaoming|

-- SELECT * FROM money m ;

id|u_id|total|
--+----+-----+
 1|   1|   10|

然后我們在userMapper中寫了這樣一條關聯查詢的SQL并開啟二級緩存:

    <select id="selectByUserId" resultType="com.sharkChili.domain.User">
      select u.id id, u.name name , m.total total
      from user u
             inner join money m on u.id = m.u_id
      where u.id = #{id}
    </select>

然后我們執行下面這段操作:

  • 通過關聯查詢獲取用戶1的姓名和關聯表的金額信息。
  • 通過moneyMapper更新用戶1對應余額。
  • 通過二級緩再次查詢。

那么問題來了,第二次查詢的金額會是更新后的10嗎?

UserMapper userMapper = SpringUtil.getBean(UserMapper.class);
        User user = new User();
        user.setId(1L);
        //第一次查詢
        User u = userMapper.selectByUserId(user);
        log.info("user:{}", JSONUtil.toJsonStr(u));
        //更新用戶1對應的余額信息
        MoneyMapper moneyMapper = SpringUtil.getBean(MoneyMapper.class);
        Money money = new Money();
        money.setId(1L);
        money.setTotal(10L);
        moneyMapper.updateByPrimaryKeySelective(money);

        //第二次查詢
        User u2 = userMapper.selectByUserId(user);
        log.info("user:{}", JSONUtil.toJsonStr(u2));

答案是還是走了臟緩存:

2024-12-13 12:22:09.286 DEBUG 9056 --- [           main] c.s.mapper.UserMapper.selectByUserId     : ==>  Preparing: select u.id id, u.name name , m.total total from user u inner join money m on u.id = m.u_id where u.id = ?
2024-12-13 12:22:09.307 DEBUG 9056 --- [           main] c.s.mapper.UserMapper.selectByUserId     : ==> Parameters: 1(Long)
2024-12-13 12:22:09.325 DEBUG 9056 --- [           main] c.s.mapper.UserMapper.selectByUserId     : <==      Total: 1
2024-12-13 12:22:09.379  INFO 9056 --- [           main] com.sharkChili.WebApplication            : user:{"id":1,"name":"xiaoming","total":50}
2024-12-13 12:22:09.394 DEBUG 9056 --- [           main] c.s.m.M.updateByPrimaryKeySelective      : ==>  Preparing: update money SET total = ? where id = ?
2024-12-13 12:22:09.394 DEBUG 9056 --- [           main] c.s.m.M.updateByPrimaryKeySelective      : ==> Parameters: 10(Long), 1(Long)
2024-12-13 12:22:09.402 DEBUG 9056 --- [           main] c.s.m.M.updateByPrimaryKeySelective      : <==    Updates: 1
2024-12-13 12:22:09.403 DEBUG 9056 --- [           main] com.sharkChili.mapper.UserMapper         : Cache Hit Ratio [com.sharkChili.mapper.UserMapper]: 0.5
2024-12-13 12:22:09.403  INFO 9056 --- [           main] com.sharkChili.WebApplication            : user:{"id":1,"name":"xiaoming","total":50}

原因也很簡單,二級緩存是以namespace為區域劃分,這意味著userMapper緩存的數據不會因為moneyMapper的改變而觸發更新,這意味著如果涉及關聯查詢的緩存數據可能會因為關聯表的更新無法感知而出現臟緩存:

解決方案也很簡單,我們只要確保緩存更新被關聯表時,及時刷新響應緩存即可,具體可以參考這篇文章

MyBatis 二級緩存 關聯刷新實現:https://blog.csdn.net/qq_37217713/article/details/123288123

8. 二級緩存的配置參數

主要參數有這么四個:

  • 緩存回收策略(eviction):這個參數有這么4個LRU最近最少回收算法這種是默認的算法、FIFO先進先出算法、SOFT算法(基于垃圾回收器算法和軟引用回收的對象)、WEAK算法即基于垃圾回收器算法和弱引用規則回收對象。
  • 刷新間隔(flushInterval):單位毫秒。
  • 容量(size):引用數目,正整數。
  • 是否只讀(readOnly):如果只讀則直接返回緩存實例,性能上會相對有些優勢。若不為只讀則會通過序列化獲取對象的拷貝,性能就相對差一些。

配置范例如下所示:

 <cache eviction="FIFO"
           flushInterval="60000"
           size="512"
           readOnly="true"/>

9. 二級緩存的失效場景

有兩種情況一種是第一次查詢的sqlsession沒有提交或者關閉:

   User1 user1 = user1Mapper.select("1");
        logger.info("二級緩存第一次查詢:[{}]", user1);




        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        User1Mapper user1Mapper1 = sqlSession2.getMapper(User1Mapper.class);
        User1 user13 = user1Mapper1.select("1");
        logger.info("二級緩存第二次查詢:[{}]", user13);

輸出結果:

2022-11-29 01:05:43,339 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==>  Preparing: select * from user1 where id = ?
2022-11-29 01:05:43,363 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==> Parameters: 1(String)
2022-11-29 01:05:43,502 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - <==      Total: 1
2022-11-29 01:05:43,506 [main] DEBUG [com.sharkchili.mapper.User1Mapper] - Cache Hit Ratio [com.sharkchili.mapper.User1Mapper]: 0.0
2022-11-29 01:05:43,506 [main] DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Opening JDBC Connection
[main] INFO com.sharkchili.mapper.MyBatisTest - 二級緩存第一次查詢:[User1{id='1', name='小明', user2=null}]
2022-11-29 01:05:44,234 [main] DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Created connection 550668305.
2022-11-29 01:05:44,234 [main] DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@20d28811]
2022-11-29 01:05:44,351 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==>  Preparing: select * from user1 where id = ?
2022-11-29 01:05:44,351 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==> Parameters: 1(String)
2022-11-29 01:05:44,465 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - <==      Total: 1
[main] INFO com.sharkchili.mapper.MyBatisTest - 二級緩存第二次查詢:[User1{id='1', name='小明', user2=null}]

第二種則是常規更新操作:

2022-11-29 01:07:22,302 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==>  Preparing: select * from user1 where id = ?
2022-11-29 01:07:22,326 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==> Parameters: 1(String)
2022-11-29 01:07:22,456 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - <==      Total: 1
[main] INFO com.sharkchili.mapper.MyBatisTest - 二級緩存第一次查詢:[User1{id='1', name='小明', user2=null}]
2022-11-29 01:07:22,479 [main] DEBUG [com.sharkchili.mapper.User1Mapper.updatebySet] - ==>  Preparing: update user1 SET id=?, name=? where id=?
2022-11-29 01:07:22,479 [main] DEBUG [com.sharkchili.mapper.User1Mapper.updatebySet] - ==> Parameters: 1(String), aa(String), 1(String)
2022-11-29 01:07:22,713 [main] DEBUG [com.sharkchili.mapper.User1Mapper.updatebySet] - <==    Updates: 1
2022-11-29 01:07:22,714 [main] DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Rolling back JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@f8c1ddd]
2022-11-29 01:07:22,833 [main] DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@f8c1ddd]
2022-11-29 01:07:22,949 [main] DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@f8c1ddd]
2022-11-29 01:07:22,949 [main] DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Returned connection 260840925 to pool.
2022-11-29 01:07:22,949 [main] DEBUG [com.sharkchili.mapper.User1Mapper] - Cache Hit Ratio [com.sharkchili.mapper.User1Mapper]: 0.0
2022-11-29 01:07:22,949 [main] DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Opening JDBC Connection
2022-11-29 01:07:22,949 [main] DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Checked out connection 260840925 from pool.
2022-11-29 01:07:22,949 [main] DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@f8c1ddd]
2022-11-29 01:07:23,065 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==>  Preparing: select * from user1 where id = ?
2022-11-29 01:07:23,065 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - ==> Parameters: 1(String)
[main] INFO com.sharkchili.mapper.MyBatisTest - 二級緩存第二次查詢:[User1{id='1', name='小明', user2=null}]
2022-11-29 01:07:23,184 [main] DEBUG [com.sharkchili.mapper.User1Mapper.select] - <==      Total: 1

要想真正用上二級緩存,需要像這樣及時提交或者關閉其他session:

User1 user1 = user1Mapper.select("1");
        logger.info("二級緩存第一次查詢:[{}]", user1);


        if (sqlSession != null) {
            sqlSession.close();
        }

        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        User1Mapper user1Mapper1 = sqlSession2.getMapper(User1Mapper.class);
        User1 user13 = user1Mapper1.select("1");
        logger.info("二級緩存第二次查詢:[{}]", user13);



        if (sqlSession2 != null) {
            sqlSession2.close();
        }

10. Mybatis一級緩存和二級緩存的區別

一級緩存默認開啟,作用域session,當session調用close或者flush時就會被清空,緩存也是PerpetualCache 一種基于HashMap實現的緩存。 而二級緩存作用于mapper(namespace),也是基于緩存也是PerpetualCache ,默認不開啟,需要緩存的屬性類必須實現序列化接口即繼承Serializable,而且二級緩存可以自定義緩存存儲源。

責任編輯:趙寧寧 來源: 寫代碼的SharkChili
相關推薦

2024-12-23 06:40:00

2023-06-27 08:37:35

Java反射動態代理機制

2010-03-01 17:57:11

WCF緩存機制

2021-07-22 09:55:28

瀏覽器前端緩存

2023-09-12 14:56:13

MyBatis緩存機制

2025-02-12 00:29:58

2022-02-15 11:49:08

eBPFGo內存

2011-12-22 14:27:11

2013-07-15 11:03:52

802.11ac技術802.11ac

2015-12-30 14:16:05

iOS動畫視圖渲染

2009-02-03 14:00:20

PHP運行PHP調用PHP原理

2015-12-23 09:16:33

ios動畫渲染機制

2009-11-12 14:32:00

BGP路由協議

2009-11-27 10:37:41

GPRS路由

2010-02-04 16:52:01

多層交換技術

2010-11-29 11:22:36

SYBASE數據庫日志

2010-08-04 09:43:28

Flex應用程序

2009-12-09 10:07:19

Linux靜態路由

2022-10-20 18:00:00

MyBatis緩存類型

2009-06-17 15:43:03

Hibernate緩存
點贊
收藏

51CTO技術棧公眾號

欧美一级生活片| 国产三级欧美三级日产三级99| 欧美日韩国产二区| 91玉足脚交白嫩脚丫| 国产精品一区二区av影院萌芽| 国产午夜精品一区二区三区视频| 91亚洲精品一区| 美日韩一二三区| 99久久99热这里只有精品| 亚洲电影天堂av| av网站在线不卡| av2020不卡| 国产日产欧美一区二区三区| 97免费资源站| 一级全黄裸体免费视频| 亚洲精品系列| 久久视频在线播放| 伊人网伊人影院| eeuss鲁片一区二区三区| 欧美午夜精品免费| 奇米精品一区二区三区| 欧洲s码亚洲m码精品一区| 91福利精品在线观看| 成人国产电影网| 26uuu日韩精品一区二区| 熟女少妇a性色生活片毛片| 最新av电影网站| 一区二区免费| 欧美精品三级在线观看| 亚洲美女区一区| 久久久久久久有限公司| av小说天堂网| 麻豆国产欧美一区二区三区| 日本国产精品视频| 狠狠躁夜夜躁人人爽天天高潮| 亚洲国产精品久久久久蝴蝶传媒| 中国日韩欧美久久久久久久久| 一区二区视频观看| 国产精品成人自拍| 日韩一级二级三级| 人人爽人人爽av| 农村妇女一区二区| 欧美性猛交xxxxxx富婆| 欧美激情国产精品日韩| 两个人看的在线视频www| 亚洲午夜久久久久| 国产手机免费视频| 黄色影院在线看| 亚洲精品免费在线播放| 伊人久久大香线蕉综合75| av在线播放网站| 国产欧美日韩精品一区| 午夜精品电影在线观看| 成人在线免费观看| 国产精品卡一卡二卡三| 亚洲一区bb| 888av在线| 自拍偷拍国产亚洲| 国产又粗又爽又黄的视频| 大片免费在线看视频| 亚洲猫色日本管| 亚洲激情免费视频| 金瓶狂野欧美性猛交xxxx| 亚洲男帅同性gay1069| 久久久国内精品| 国产精品一品| 欧美天堂在线观看| 亚洲欧美激情网| 精品69视频一区二区三区| 欧美精品丝袜久久久中文字幕| 少妇网站在线观看| 欧美一级大片在线视频| 亚洲精品一区二区在线观看| v天堂中文在线| 国产传媒欧美日韩成人精品大片| 在线日韩第一页| 91嫩草丨国产丨精品| 午夜国产精品视频| 欧美最顶级丰满的aⅴ艳星| 中文字幕乱伦视频| 国产精品一区不卡| 精品日本一区二区| 色综合久久久久综合一本到桃花网| ㊣最新国产の精品bt伙计久久| 成人高清dvd| 在线高清av| 欧美日韩视频在线观看一区二区三区| 中文字幕剧情在线观看| 欧美日韩导航| 中文字幕久热精品在线视频| 欧美色图亚洲天堂| 国产欧美短视频| 国产免费一区二区三区在线观看| 超碰在线人人干| 久久综合色8888| 韩国黄色一级大片| 国产伦久视频在线观看| 欧美日韩aaa| 国产精品成人99一区无码| 欧美丝袜激情| 久久久久中文字幕2018| 伊人久久亚洲综合| 99久久精品国产观看| 亚洲人成网站在线观看播放 | 99久久国产综合精品女不卡| 亚洲欧洲日本国产| а√在线中文网新版地址在线| 欧美三区在线视频| 欧美深性狂猛ⅹxxx深喉| 91亚洲国产| 日本不卡视频在线播放| 亚洲乱码国产乱码精品精软件| 国产情人综合久久777777| 国产91在线亚洲| 成人精品动漫| 国产手机视频精品| 免费一级片在线观看| 美女在线视频一区| 免费不卡亚洲欧美| 91资源在线观看| 777奇米成人网| 一级特黄曰皮片视频| 一区二区三区高清视频在线观看| 亚洲一区亚洲二区| 日本在线观看网站| 欧美中文字幕久久| 亚洲第一页av| 一区二区三区四区五区精品视频 | 亚洲视频天天射| 久久久久久久久久久久久久久久久久| 欧洲亚洲妇女av| 女人18毛片水真多18精品| 亚洲免费观看高清完整版在线| 国产成人黄色网址| 精品国产中文字幕第一页| 欧美亚洲国产日本| 视频福利在线| 黑丝美女久久久| 亚洲成av人片在线观看无| 欧美日韩mv| 99re热精品| 日本大胆在线观看| 日韩欧美国产一二三区| 成人性生活毛片| 国产一区三区三区| 9999在线观看| 国产精品1区在线| 久久久国产精品亚洲一区| 在线免费a视频| 国产精品热久久久久夜色精品三区| 91视频免费版污| 欧美一区二区三区高清视频| 国产精品高潮粉嫩av| 第九色区av在线| 欧美调教femdomvk| 欧美a级片免费看| 精品一区二区三区在线观看国产 | 国产日本精品| 欧美久久久久久| 欧美日韩免费观看视频| 中文字幕亚洲综合久久| 97精品人妻一区二区三区香蕉| 中文字幕视频一区| 午夜诱惑痒痒网| 国产精品videosex极品| 国产亚洲欧美一区二区三区| 麻豆免费在线| 亚洲视频自拍偷拍| 一个人看的www日本高清视频| 自拍偷拍国产精品| 国产性生活毛片| 玖玖在线精品| 自拍偷拍一区二区三区| 99久久人爽人人添人人澡| 欧美亚洲国产日本| 日本在线视频站| 精品不卡在线视频| 欧美性猛交xxxx乱大交hd| 综合色中文字幕| 国产一级黄色录像| 石原莉奈一区二区三区在线观看| 在线观看精品视频| 嗯用力啊快一点好舒服小柔久久| 91国在线精品国内播放| 大胆av不用播放器在线播放| 欧美一级视频精品观看| 欧美性猛交bbbbb精品| 国产精品久久影院| 99精品一区二区三区无码吞精| 日日摸夜夜添夜夜添国产精品 | 在线不卡日本v二区707| 日韩精品在线观看一区二区| 6—12呦国产精品| 亚洲成人中文在线| av在线免费播放网址| 成人动漫一区二区在线| 波多野结衣xxxx| 亚洲国内精品| 老汉色影院首页| 亚洲三级网页| 国产精品v欧美精品v日韩精品| 成人看片网站| 97国产精品久久| 羞羞视频在线免费国产| 亚洲视频欧美视频| xxxx国产精品| 欧美日韩视频第一区| 国产特黄大片aaaa毛片| 亚洲少妇30p| 精品成人无码一区二区三区| 成人久久18免费网站麻豆 | 国产天堂第一区| 亚洲一区二区偷拍精品| 日韩欧美视频免费观看| 91亚洲国产成人精品一区二区三| 精品国产午夜福利在线观看| 日韩av一级电影| 欧美啪啪免费视频| 欧美成人有码| 亚洲日本精品一区| 国产成人精品999在线观看| 国产精品一 二 三| 午夜免费欧美电影| 91精品国产综合久久香蕉922| 日韩a**中文字幕| 青青a在线精品免费观看| 成人免费高清观看| 欧美高清不卡在线| 香蕉成人app免费看片| 久久精品国产91精品亚洲| av在线1区2区| 日韩在线精品一区| av网站在线免费观看| 伊人伊人伊人久久| 高清国产福利在线观看| 国产视频久久网| 日韩欧美在线观看一区二区| 亚洲国产欧美一区二区三区同亚洲 | 国产三区精品| 免费观看成人www动漫视频| 俄罗斯精品一区二区| theporn国产在线精品| 成人动漫视频在线观看免费| 欧美第一在线视频| 99国产超薄肉色丝袜交足的后果| 精品视频一二| 成人资源av| 精品自拍偷拍| 久久涩涩网站| 国产探花一区二区| 色一情一区二区三区四区| 郴州新闻综合频道在线直播| 亚洲欧洲久久| 欧美福利视频| 大西瓜av在线| 国产美女诱惑一区二区| 免费在线激情视频| 天堂资源在线中文精品| 牛夜精品久久久久久久| 蜜臀久久99精品久久久久宅男| 欧美成人三级在线播放| 国产精品一区在线| 男女一区二区三区| 国产农村妇女毛片精品久久麻豆 | 欧美xxxxxxxx| 性猛交xxxx| 在线看福利67194| 18加网站在线| 欧美亚洲在线视频| 美女视频一区| 国产日韩在线一区二区三区| 国产在线观看91一区二区三区| 在线精品亚洲一区二区| 激情欧美国产欧美| 性欧美极品xxxx欧美一区二区| 久久国产生活片100| 中文字幕无人区二| 久久日一线二线三线suv| 国产视频精品免费| 亚洲一区成人在线| 亚洲精品毛片一区二区三区| 8v天堂国产在线一区二区| 日韩在线观看视频一区二区三区 | 一级肉体全黄裸片| 亚洲另类在线一区| 国内自拍视频在线播放| 4438成人网| 欧美色18zzzzxxxxx| 精品精品国产国产自在线| 久草成色在线| 国产精品欧美在线| 国产香蕉精品| 亚洲精品无人区| 亚洲精品123区| 免费成人黄色大片| 91欧美激情一区二区三区成人| 成人一级黄色大片| 一本久久精品一区二区| www视频在线| www.国产一区| 婷婷激情一区| 国产精品一区在线观看| 99久久99热这里只有精品 | 日韩另类视频| 黑人中文字幕一区二区三区| 欧美成人milf| 毛片av免费在线观看| 成人黄色网址在线观看| 最新av电影网站| 欧美三级视频在线| 青青草娱乐在线| 久久久久久久久久国产精品| 91精品国产色综合久久不卡粉嫩| 麻豆av一区二区三区| 黄色av日韩| 天天操夜夜操很很操| 中文字幕成人在线观看| 伊人手机在线视频| 亚洲国产成人久久综合一区| 91网址在线观看| 91免费综合在线| 99精品视频在线观看播放| 亚洲成人福利在线观看| 久久久久久久久久电影| 国产手机在线视频| 精品国产乱码91久久久久久网站| 麻豆视频免费在线观看| 国产精品专区一| 成人av国产| 另类小说色综合| 国产欧美精品国产国产专区 | 色一情一乱一伦一区二区三区丨| 美女久久网站| 泷泽萝拉在线播放| 欧美丝袜美女中出在线| 你懂的视频在线免费| 欧美一二三视频| 三级精品视频| 黄色影院一级片| 久久伊人蜜桃av一区二区| 日韩成人一区二区三区| 精品动漫一区二区三区在线观看| 色噜噜狠狠狠综合欧洲色8| 操人视频欧美| 国产主播精品| 丰满岳乱妇一区二区| 亚洲成人一区在线| 无码国产色欲xxxx视频| 456亚洲影院| 精品国产一区二区三区四区| 手机视频在线观看| 中文字幕日韩一区| aaa一区二区三区| 欧美国产日本高清在线| 国产成人av毛片| 无罩大乳的熟妇正在播放| 91麻豆免费观看| 国产日韩久久久| 日韩在线视频免费观看| 清纯唯美激情亚洲| 成人免费观看cn| 国产嫩草影院久久久久| 91精品国产乱码久久久| 欧美剧在线观看| 色老板在线视频一区二区| 免费大片在线观看| 亚洲欧洲国产专区| 国产91免费看| 欧洲成人在线观看| 天天综合精品| 成人免费看片载| 在线欧美日韩国产| www视频在线看| 精品视频免费观看| 免播放器亚洲一区| 日韩免费一二三区| 尤物tv国产一区| 一区二区三区在线免费看| 一区二区传媒有限公司| 中文字幕一区不卡| 少妇人妻一区二区| 国产精品伦子伦免费视频| 国产在线不卡| 无码人中文字幕| 亚洲成人免费在线视频| 国产亚洲欧美日韩精品一区二区三区 | 97在线精品国自产拍中文| 欧美黑人巨大videos精品| 欧美激情精品久久久久久免费印度 | 毛片电影在线| 在线观看成人av电影| 99久久久精品| 国产强伦人妻毛片| 欧美最猛性xxxxx免费| 一级毛片免费高清中文字幕久久网| 在线观看国产三级| 欧美高清你懂得| 欧美magnet| 成人免费毛片在线观看| 国产精品对白交换视频|