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

Mybatis原理及源碼分析

開發 后端
作為Java程序員Mybatis應該是一個必會框架了,其源碼體量只有Spring 的1/5,也是Hibernate的1/5 ,相比于其他流行框架Mybatis源碼無疑是學習成本最低的,當做年輕人看的第一個框架源碼,無疑是非常好的。

[[416230]]

本文轉載自微信公眾號「三不猴子」,作者sanbuhouzi。轉載本文請聯系三不猴子公眾號。

作為Java程序員Mybatis應該是一個必會框架了,其源碼體量只有Spring 的1/5,也是Hibernate的1/5 ,相比于其他流行框架Mybatis源碼無疑是學習成本最低的,當做年輕人看的第一個框架源碼,無疑是非常好的。

整體架構

對于一個陌生的事物切勿一頭扎進細節里,我們先要觀其大概看看架構脈絡,MyBatis 分為三層架構,分別是基礎支撐層、核心處理層和接口層。

Mybatis 整體架構

基礎支撐層

基礎支撐層是這個Mybatis框架的基建,為整個Mybatis框架提供非常基礎的功能。(篇幅有限下面我們只對部分模塊做簡單的分析)

1.類型轉換模塊,我們在Mybatis中使用< typeAliase >標簽定義一個別名就是使用類型轉換模塊實現的。類型轉換模塊最重要的功能還是實現了Mybatis中JDBC類型和Java類型之間的轉換。主要體現在:

  • 在SQL模板綁定用戶參入實參的場景中,將Java類型轉換成JDBC類型
  • 在結果集中,將JDBC類型轉換成Java類型。

Mybatis類型轉換

2.日志模塊,產生日志,定位異常。

3.反射工具,對原生的Java反射作了一些封裝。

4.Binding模塊,我們在執行Mybatis中的方法時都是通過SqlSession來獲Mapper接口中的代理,這個代理將Mapper.xml文件中SQL進行關聯就是通過Binding模塊來實現的。值得注意點是這個過程是發生在編譯期。可以將錯誤提前到編譯期。

5.數據源模塊,數據源對于一個ORM來說算是非常核心的組件之一了。Mybatis默認的數據源是非常出色的,Mybatis同時也支持集成第三方的數據源。

6.緩存模塊,緩存模塊的好壞直接影響這個ORM的性能。Mybatis提供了兩級緩存,同時也支持第三方緩存中間件集成。

Mybatis緩存

7.解析器模塊,主要是config.xml配置文件解析,和mapper.xml文件解析。

8.事務管理模塊,事務模塊對數據庫的事務機制進行控制,對數據庫事務進行了抽象,同時也對spring框架進行了整合。詳細的處理邏輯下文會結合源碼詳細解析。

核心處理層

核心處理層是我們在學習Mybatis原理的時候需要花80%時間的地方。核心處理層是 MyBatis 核心實現所在,其中涉及 MyBatis 的初始化以及執行一條 SQL 語句的全流程。

配置解析

MyBatis 的初始化以及執行一條 SQL 語句的全流程中也包含了配置解析,我們在現實開發中一般都是使用spring boot starter的自動配置。我們一項目啟動為起點一層一層剝開Mybatis的流程。先打開org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration首先明確一點就是MybatisAutoConfiguration的目的就是要得到一個SqlSessionFactory。

  1. @Bean 
  2. @ConditionalOnMissingBean 
  3. public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { 
  4.   SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); 
  5.   factory.setDataSource(dataSource); 
  6.   factory.setVfs(SpringBootVFS.class); 
  7.   if (StringUtils.hasText(this.properties.getConfigLocation())) { 
  8.     factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); 
  9.   } 
  10.   Configuration configuration = this.properties.getConfiguration(); 
  11.   if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { 
  12.     configuration = new Configuration(); 
  13.   } 
  14.   if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { 
  15.     for (ConfigurationCustomizer customizer : this.configurationCustomizers) { 
  16.       customizer.customize(configuration); 
  17.     } 
  18.   } 
  19.   factory.setConfiguration(configuration); 
  20.   if (this.properties.getConfigurationProperties() != null) { 
  21.     factory.setConfigurationProperties(this.properties.getConfigurationProperties()); 
  22.   } 
  23.   if (!ObjectUtils.isEmpty(this.interceptors)) { 
  24.     factory.setPlugins(this.interceptors); 
  25.   } 
  26.   if (this.databaseIdProvider != null) { 
  27.     factory.setDatabaseIdProvider(this.databaseIdProvider); 
  28.   } 
  29.   if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { 
  30.     factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); 
  31.   } 
  32.   if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { 
  33.     factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); 
  34.   } 
  35.   if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { 
  36.     factory.setMapperLocations(this.properties.resolveMapperLocations()); 
  37.   } 
  38.  
  39.   return factory.getObject(); 

這里是通過MybatisProperties里面的配置并放入到SqlSessionFactoryBean中,再由SqlSessionFactoryBean得到SqlSessionFactory。看到最后一行return factory.getObject();我們進去看看這個factory.getObject()的邏輯是如何得到一個SqlSessionFactory。

  1. @Override 
  2. public SqlSessionFactory getObject() throws Exception { 
  3.   if (this.sqlSessionFactory == null) { 
  4.     afterPropertiesSet(); 
  5.   } 
  6.  
  7.   return this.sqlSessionFactory; 

這一步沒什么好說的,看看afterPropertiesSet()方法

  1. @Override 
  2. public void afterPropertiesSet() throws Exception { 
  3.   notNull(dataSource, "Property 'dataSource' is required"); 
  4.   notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required"); 
  5.   state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null), 
  6.             "Property 'configuration' and 'configLocation' can not specified with together"); 
  7.  
  8.   this.sqlSessionFactory = buildSqlSessionFactory(); 

重點來了,看看這個buildSqlSessionFactory()方法這里的核心目的就是將configurationProperties解析到Configuration對象中。代碼太長了我就不貼出來了, buildSqlSessionFactory()的邏輯我畫了個圖,有興趣的小伙伴自行看一下。

Mybatis配置解析1

我們不要陷入細節之中,我們看看中點看看buildSqlSessionFactory() 方法的最后一行this.sqlSessionFactoryBuilder.build(configuration)點進去

  1. public SqlSessionFactory build(Configuration config) { 
  2.     return new DefaultSqlSessionFactory(config); 
  3.   } 

通過buildSqlSessionFactory()解析得到的Configuration對象創建一個DefaultSqlSessionFactory(config),到此我們就得到了SqlSessionFactory同時被配置成一個bean了。

我們最終操作都是SqlSession,什么時候會通過SqlSessionFactory得到一個SqlSession呢?

要解決這個問題我們回到最開始的MybatisAutoConfiguration的sqlSessionTemplate(SqlSessionFactory sqlSessionFactory)這個方法,點開SqlSessionTemplate發現它是一個實現了SqlSession到這里我們猜測就是在這里SqlSessionFactory會構建一個SqlSession出來。我們進入new SqlSessionTemplate(sqlSessionFactory)看看源碼。

  1. public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { 
  2.    this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); 
  3.  } 

再往下看,我們就看到了

  1. public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, 
  2.     PersistenceExceptionTranslator exceptionTranslator) { 
  3.  
  4.   notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required"); 
  5.   notNull(executorType, "Property 'executorType' is required"); 
  6.  
  7.   this.sqlSessionFactory = sqlSessionFactory; 
  8.   this.executorType = executorType; 
  9.   this.exceptionTranslator = exceptionTranslator; 
  10.   this.sqlSessionProxy = (SqlSession) newProxyInstance( 
  11.       SqlSessionFactory.class.getClassLoader(), 
  12.       new Class[] { SqlSession.class }, 
  13.       new SqlSessionInterceptor()); 

這里通過動態代理創建了一個SqlSession。

參數映射、SQL解析

我們先看一下MapperFactoryBean類,這個類實現了FactoryBean在bean初始化的時候會調用getObject()方法我們看看這個類下重寫的getObject()方法里的內容。

  1. @Override 
  2.  public T getObject() throws Exception { 
  3.    return getSqlSession().getMapper(this.mapperInterface); 
  4.  } 

這里調用了sqlSession的getMapper()方法。一層一層點進去里面返回的是一個代理對象。最后的執行是由MapperProxy執行。

  1. public <T> T getMapper(Class<T> type, SqlSession sqlSession) { 
  2.     final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type); 
  3.     if (mapperProxyFactory == null) { 
  4.       throw new BindingException("Type " + type + " is not known to the MapperRegistry."); 
  5.     } 
  6.     try { 
  7.       return mapperProxyFactory.newInstance(sqlSession); 
  8.     } catch (Exception e) { 
  9.       throw new BindingException("Error getting mapper instance. Cause: " + e, e); 
  10.     } 
  11.   } 

接下來的流程我還是畫個流程圖,防止小伙伴們走丟。我這里的內容可能未必完全和小標題一樣,我主要按照sql執行的流程講解的。

Mybatis參數綁定

先看一下MapperProxy中的invoke方法,cachedMapperMethod()方法將MapperMethod緩存起來了。

  1. @Override 
  2. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
  3.   try { 
  4.     if (Object.class.equals(method.getDeclaringClass())) { 
  5.       return method.invoke(this, args); 
  6.     } else if (isDefaultMethod(method)) { 
  7.       return invokeDefaultMethod(proxy, method, args); 
  8.     } 
  9.   } catch (Throwable t) { 
  10.     throw ExceptionUtil.unwrapThrowable(t); 
  11.   } 
  12.   final MapperMethod mapperMethod = cachedMapperMethod(method); 
  13.   return mapperMethod.execute(sqlSession, args); 
  14.  
  15.  private MapperMethod cachedMapperMethod(Method method) { 
  16.     MapperMethod mapperMethod = methodCache.get(method); 
  17.     if (mapperMethod == null) { 
  18.       mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()); 
  19.       methodCache.put(method, mapperMethod); 
  20.     } 
  21.     return mapperMethod; 
  22.   } 

我們在往下看mapperMethod.execute(sqlSession, args)方法。

  1. public Object execute(SqlSession sqlSession, Object[] args) { 
  2.   Object result; 
  3.   switch (command.getType()) { 
  4.     case INSERT: { 
  5.     Object param = method.convertArgsToSqlCommandParam(args); 
  6.       result = rowCountResult(sqlSession.insert(command.getName(), param)); 
  7.       break; 
  8.     } 
  9.     case UPDATE: { 
  10.       Object param = method.convertArgsToSqlCommandParam(args); 
  11.       result = rowCountResult(sqlSession.update(command.getName(), param)); 
  12.       break; 
  13.     } 
  14.     case DELETE: { 
  15.       Object param = method.convertArgsToSqlCommandParam(args); 
  16.       result = rowCountResult(sqlSession.delete(command.getName(), param)); 
  17.       break; 
  18.     } 
  19.     case SELECT
  20.       if (method.returnsVoid() && method.hasResultHandler()) { 
  21.         executeWithResultHandler(sqlSession, args); 
  22.         result = null
  23.       } else if (method.returnsMany()) { 
  24.         result = executeForMany(sqlSession, args); 
  25.       } else if (method.returnsMap()) { 
  26.         result = executeForMap(sqlSession, args); 
  27.       } else if (method.returnsCursor()) { 
  28.         result = executeForCursor(sqlSession, args); 
  29.       } else { 
  30.         Object param = method.convertArgsToSqlCommandParam(args); 
  31.         result = sqlSession.selectOne(command.getName(), param); 
  32.       } 
  33.       break; 
  34.     case FLUSH: 
  35.       result = sqlSession.flushStatements(); 
  36.       break; 
  37.     default
  38.       throw new BindingException("Unknown execution method for: " + command.getName()); 
  39.   } 
  40.   if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) { 
  41.     throw new BindingException("Mapper method '" + command.getName()  
  42.         + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); 
  43.   } 
  44.   return result; 

method.convertArgsToSqlCommandParam(args)這里就是處理參數轉換的邏輯。還有很多細節由于篇幅有限以及時間倉促我們不做過多的贅述,感興趣的小伙伴可以結合上面的圖自己看看。下面我們看SQL的執行流程是怎么樣的。整體流程如下圖。

Mybatis執行流程

我們就不對每一個執行器都分析,我只挑一個SimpleExecutor來具體跟一下源碼。我們還是先看看圖吧,防止自己把自己搞蒙。

以simpleExecutor為例的執行流程

  1. @Override 
  2. public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { 
  3.   Statement stmt = null
  4.   try { 
  5.     Configuration configuration = ms.getConfiguration(); 
  6.     StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); 
  7.     stmt = prepareStatement(handler, ms.getStatementLog()); 
  8.     return handler.<E>query(stmt, resultHandler); 
  9.   } finally { 
  10.     closeStatement(stmt); 
  11.   } 

這里獲取了Configuration,創建了一個StatementHandler,預處理操作,具體執行的根據創建的預處理方法,最后執行query方法

  1. @Override 
  2. public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException { 
  3.   String sql = boundSql.getSql(); 
  4.   statement.execute(sql); 
  5.   return resultSetHandler.<E>handleResultSets(statement); 

 

到此我們整理了整個Mybatis的執行流程,分析了其中的源碼,由于篇幅有限很多地方都沒有細致的分析,但是也貼出了圖,希望能幫助到你。

 

責任編輯:武曉燕 來源: 三不猴子
相關推薦

2019-11-25 16:05:20

MybatisPageHelpeJava

2019-10-16 16:33:41

Docker架構語言

2019-09-20 08:54:38

KafkaBroker消息

2021-07-03 15:22:02

Mybatis InsID源碼

2014-12-11 13:37:13

WPF架構

2021-11-26 17:17:43

Android廣播運行原理源碼分析

2023-04-28 08:30:56

MyBatis架構API

2012-02-23 12:53:40

JavaPlay Framew

2023-11-06 18:37:23

虛擬線程編寫

2021-09-05 07:35:58

lifecycleAndroid組件原理

2021-04-28 06:26:11

Spring Secu功能實現源碼分析

2020-12-17 08:02:42

MyBatis插件框架

2024-04-11 11:04:05

Redis

2021-12-06 14:52:08

動畫Android補間動畫

2015-11-23 09:50:15

JavaScript模塊化SeaJs

2015-03-17 09:44:08

2022-06-30 10:38:53

Lepton無損壓縮圖片圖片質量

2019-02-26 15:15:16

DNS漏洞IP

2019-04-02 08:30:03

2017-03-17 19:59:39

點贊
收藏

51CTO技術棧公眾號

日韩精品在线网站| 国产精品理论在线观看| 欧美在线免费观看| 国产又粗又猛又爽又黄的视频小说| 国产黄色免费视频| 久久国产电影| 337p日本欧洲亚洲大胆精品| 日韩中文字幕二区| av观看在线| 91麻豆文化传媒在线观看| 成人av电影天堂| 日本在线免费观看| 婷婷精品进入| 日韩精品久久久久| 日韩精品在线播放视频| 三上悠亚亚洲一区| 一区二区三区四区av| 日韩妆和欧美的一区二区| 精品久久在线观看| 日韩电影免费在线| 久久久久国产精品一区| 五月天婷婷丁香网| 蜜桃a∨噜噜一区二区三区| 日韩免费看网站| 亚洲精品中文字幕无码蜜桃| 日韩激情av| 国产日韩综合av| 九色91在线视频| 精品女同一区二区三区| 蜜臀av性久久久久蜜臀aⅴ流畅| 久久人人爽人人| 欧美大片xxxx| 欧美一区二区三区激情视频| 亚洲精品国产综合区久久久久久久| 手机av在线免费| 亚洲不卡系列| 色综合天天综合色综合av| 男人添女荫道口图片| 黄色成年人视频在线观看| 男女男精品视频| 91精品国产色综合久久不卡98| 国产成人av免费在线观看| 欧美久久精品一级c片| 亚洲精品综合久久中文字幕| 国产真实乱人偷精品| youjizzjizz亚洲| 日韩欧美激情一区| 永久免费黄色片| 高清国产一区二区三区四区五区| 欧美日韩美少妇| 中文字幕一区二区三区四区在线视频| 粉嫩一区二区| 色拍拍在线精品视频8848| 欧美日韩国产精品激情在线播放| 高h视频在线播放| 一区二区三区中文在线观看| 国产一二三四区在线观看| 大片免费在线观看| 亚洲欧洲av在线| 无码人妻精品一区二区三区99v| 尤物网址在线观看| 亚洲桃色在线一区| 9191国产视频| 欧美性猛片xxxxx免费中国 | 欧美偷拍一区二区| www.色就是色| 日本成人一区二区| 91麻豆精品国产91| 日韩精品xxx| 成人资源在线播放| 日韩成人av一区| 永久免费成人代码| 日韩系列欧美系列| 欧美乱人伦中文字幕在线| 久久久久亚洲天堂| 99视频一区| 国产不卡在线观看| 亚洲系列第一页| 国产一区免费电影| 国产精品初高中精品久久| 五月天婷婷在线观看| 国产欧美一区视频| 中文字幕第一页亚洲| 久草在线视频网站| 色天天综合色天天久久| 国内国产精品天干天干| 国产无遮挡裸体免费久久| 亚洲人成网在线播放| 亚洲视频重口味| 国产精品久久| 国产精品999| 国内精品久久久久久久久久久 | 91在线中文| 舔着乳尖日韩一区| 美女在线视频一区二区| 日韩三级网址| 亚洲热线99精品视频| 网站永久看片免费| 亚洲伦伦在线| 国产在线日韩在线| 香蕉久久国产av一区二区| 国产精品区一区二区三区| 久久久国内精品| 成人不卡视频| 亚洲第一av在线| 三上悠亚在线观看视频| 亚洲一区日韩在线| 亚洲影视九九影院在线观看| 青青草娱乐在线| 亚洲精品高清视频在线观看| 熟妇人妻va精品中文字幕| 日韩三级不卡| 日韩一区在线视频| 日韩色图在线观看| 成人听书哪个软件好| 亚洲va久久久噜噜噜久久狠狠| 国产经典三级在线| 欧美卡1卡2卡| 亚洲а∨天堂久久精品2021| 一区二区亚洲精品| 亚洲tv在线观看| 成年人视频免费在线观看| 亚洲成va人在线观看| 在线观看18视频网站| 欧美三级网址| 日韩av网址在线| 久久黄色免费视频| 国产一区在线看| 色一情一乱一伦一区二区三区| 国产精品电影| 精品黑人一区二区三区久久| 亚洲精品电影院| 日本欧美一区二区三区| 久久久婷婷一区二区三区不卡| 后进极品白嫩翘臀在线播放| 欧美高清精品3d| 精品熟妇无码av免费久久| 国产精品亚洲产品| 精品蜜桃传媒| 亚洲女同志freevdieo| 91入口在线观看| 欧美日韩国产综合视频| 亚洲1区2区3区4区| 精品久久久久久无码人妻| 一区二区影视| 91亚洲va在线va天堂va国| 77导航福利在线| 欧美日韩一区二区三区在线 | 日韩中文字幕久久| 欧美视频xxxx| 国产欧美一区二区三区沐欲| 欧美成人黑人猛交| 国产探花一区在线观看| 国产精品99蜜臀久久不卡二区| 欧美18xxxxx| 在线一区二区三区| 欧美精品日韩在线| 蜜桃av噜噜一区二区三区小说| 日韩三级在线播放| 精品自拍视频| 久久国产色av| 亚洲免费不卡视频| 丁香五六月婷婷久久激情| 在线免费观看日韩av| 视频一区中文字幕国产| 日韩欧美三级一区二区| 日本午夜精品久久久久| 欧美精品免费在线观看| 六月婷婷中文字幕| 欧美日韩综合视频网址| 国产精品久久免费观看| 久久成人精品无人区| 免费久久久久久| 91国内精品白嫩初高生| 91福利视频在线观看| а天堂8中文最新版在线官网| 欧美日韩二区三区| 亚洲一区二区91| 久久久久久久久久久久久久久99| 9久久婷婷国产综合精品性色| 91精品成人| 国精产品99永久一区一区| 午夜日韩成人影院| 欧美精品在线免费观看| 日韩在线一区二区三区四区| 色视频一区二区| 欧美成人精品欧美一| 91毛片在线观看| 国产女同无遮挡互慰高潮91| 在线日韩视频| 亚洲最大免费| 欧美a大片欧美片| 国产精品一区二区三区免费视频| 美女网站视频在线| 一本色道久久综合亚洲精品小说 | 国产69精品久久99不卡| 国产原创中文在线观看| 97视频热人人精品免费| 国产一区免费| 亚洲三级在线| 国产91色在线|免| 青草青在线视频| 一区二区亚洲欧洲国产日韩| 成人免费视频国产免费麻豆| 欧美中文字幕一区| 国产成人亚洲欧洲在线| 国产精品久久久久一区| 久久国产精品影院| 成人性色生活片免费看爆迷你毛片| 亚洲xxxx2d动漫1| 91久久久久| 99久久99久久精品| 久久综合88| 欧美一区2区三区4区公司二百| 香港久久久电影| 国产日韩欧美自拍| 性感美女一区二区在线观看| 久久久久久av| 50度灰在线| 精品国产一区二区三区久久久| 美女做暖暖视频免费在线观看全部网址91| 日韩欧美黄色影院| 国产一区二区小视频| 欧洲国内综合视频| 色屁屁影院www国产高清麻豆| 亚洲国产精品自拍| 成人免费视频网站入口::| 国产精品午夜在线| 美女洗澡无遮挡| 91免费看片在线观看| 亚洲av无码一区东京热久久| 国产一区二区0| 亚洲男人天堂av在线| 男人的j进女人的j一区| 久章草在线视频| 免费欧美在线| 欧美亚洲国产成人| 亚洲欧美日本视频在线观看| 亚洲中文字幕无码专区| 国产精品亚洲产品| 波多野结衣50连登视频| 国产精品入口| 凹凸国产熟女精品视频| 国产精品普通话对白| 欧美 丝袜 自拍 制服 另类 | 成年网站在线播放| 国产精品永久| 日韩 欧美 高清| 久久精品九九| 最近中文字幕一区二区| 免费人成在线不卡| 99日在线视频| 国内精品伊人久久久久影院对白| 看看黄色一级片| 国产一区二区久久| 善良的小姨在线| 国产91对白在线观看九色| 艳妇乳肉豪妇荡乳xxx| 99久久国产综合精品色伊 | 亚洲97av| 日韩欧美精品一区二区三区经典| 日本道不卡免费一区| 中文字幕欧美日韩一区二区三区| 91精品成人| 日本香蕉视频在线观看| 亚洲高清成人| 91视频最新入口| 免费在线看成人av| 亚洲五月激情网| 成人一区二区三区视频在线观看| 波多野结衣影院| 国产亚洲美州欧州综合国| 小嫩苞一区二区三区| 亚洲一区二区三区视频在线| 在线观看亚洲天堂| 欧美日韩中文精品| 国产aⅴ爽av久久久久成人| 亚洲第一综合天堂另类专| 黄色大片在线看| 久久精品国产欧美亚洲人人爽| 国产精品实拍| 欧美中文字幕在线视频| 亚洲精品tv| 久草热久草热线频97精品| 久久理论电影| 蜜臀精品一区二区| 日韩av中文字幕一区二区三区| 无套白嫩进入乌克兰美女| 成人精品在线视频观看| 国产午夜福利一区| 亚洲主播在线观看| 91porny九色| 欧美一区二区三区在线视频| 日韩有码电影| 久久福利视频导航| 黑人巨大精品欧美一区二区桃花岛| 成人免费大片黄在线播放| 欧美日韩破处| 欧美xxxx吸乳| 丝瓜av网站精品一区二区| 免费国偷自产拍精品视频| 久久日韩精品一区二区五区| 青草影院在线观看| 在线精品亚洲一区二区不卡| 午夜精品小视频| 色婷婷综合久久久久| 午夜影院一区| 亚洲综合日韩在线| 欧洲视频一区| 国产精品333| 国产成人在线看| 97精品在线播放| 日本高清无吗v一区| 熟妇人妻系列aⅴ无码专区友真希| 久久精品在线视频| 免费观看成人性生生活片| 成人激情直播| 亚洲不卡av不卡一区二区| 激情婷婷综合网| 91丨九色丨蝌蚪丨老版| 国产一级片免费| 日韩欧美综合一区| 欧美性天天影视| 国产精品福利观看| 亚洲人成网77777色在线播放 | 久久成人免费电影| av女人的天堂| 懂色aⅴ精品一区二区三区蜜月| 午夜精品久久久久久久第一页按摩| 日韩在线播放视频| 成人综合网站| 丝袜足脚交91精品| 日日夜夜精品免费视频| 青青草福利视频| 色综合色狠狠天天综合色| 天堂av在线资源| 91大神在线播放精品| 性欧美lx╳lx╳| 国产性xxxx18免费观看视频| av电影在线观看不卡| 久久久久久久久久免费视频| 亚洲国产美女精品久久久久∴| 欧洲性视频在线播放| av一区二区三区四区电影| 欧美日韩hd| 亚洲欧美日韩偷拍| 亚洲福利视频导航| 天天操天天干天天操| 91精品国产免费久久久久久| 香蕉一区二区| 日本熟妇人妻中出| 国产精品色哟哟| 国产免费一区二区三区免费视频| 欧美不卡视频一区发布| av成人在线网站| 免费视频爱爱太爽了| 99在线精品一区二区三区| 四虎成人永久免费视频| 国产性猛交xxxx免费看久久| 精品美女一区| 日韩久久久久久久久久久久| 成人动漫精品一区二区| 精品国产aⅴ一区二区三区东京热| 一区二区三区四区激情| 神马久久久久久久久久| 青草青草久热精品视频在线网站| 激情五月综合网| 亚洲综合20p| 亚洲成人av电影在线| 你懂的视频在线观看| 国产日本欧美视频| 国产精品多人| 少妇久久久久久久久久| 7777精品伊人久久久大香线蕉| 影音先锋在线视频| 久久国产精品亚洲va麻豆| 免费在线观看一区二区三区| 久久久精品99| 亚洲色图狂野欧美| 国产精品一区免费在线 | 亚洲国产精品免费在线观看| 亚洲国产欧美自拍| 日本成人在线网站| 婷婷无套内射影院| 中文字幕一区在线观看| 蜜臀久久久久久999| 国产精品美女免费视频| 午夜国产精品视频免费体验区| 大地资源二中文在线影视观看| 欧美性感一区二区三区| av黄在线观看| 神马影院午夜我不卡影院| 国产·精品毛片| 中文在线字幕免费观| 久久免费福利视频| 久久国产成人午夜av影院宅| 日韩一级视频在线观看| 7777精品伊人久久久大香线蕉完整版| 青青青免费在线视频| 特级黄色录像片|