日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

mybatis源码刨析总结

發布時間:2024/4/19 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mybatis源码刨析总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

拉勾 mybatis

初始化

1.創建git倉庫

1.新建一個目錄 然后點擊右鍵 git base here 創建git (會彈出一個窗口)
2.初始化 再窗口輸入 git init
3.指定倉庫 git clone 倉庫地址
4.上傳文件 點擊右鍵 git提交->master (選擇提交并推送)

1. jdbc連接數據庫的缺陷

1.1 代碼

public static void main(String[] args) {Connection connection = null;PreparedStatement preparedStatement = null;ResultSet resultSet = null;try {//加載數據庫驅動Class.forName("com.mysql.jdbc.Driver");//通過驅動管理類獲取數據庫連接connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/lgstudy?characterEncoding=utf-8", "root", "root");//---有參數 // //?占位符 // String sql = "select * from user where username = ?"; // //獲取預處理statement // preparedStatement = connection.prepareStatement(sql); // // 設置參數 // preparedStatement.setString(1, "占山");//---無參數String sql = "select * from user";preparedStatement = connection.prepareStatement(sql);// 執行sql查詢結果集resultSet = preparedStatement.executeQuery();//遍歷結果集while (resultSet.next()) {int id = resultSet.getInt("id");String username = resultSet.getString("username");User user = new User();//封裝useruser.setId(id);user.setUsername(username);System.out.println(user);}} catch (Exception e) {e.printStackTrace();} finally{// 釋放資源if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if (preparedStatement != null) {try {preparedStatement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}}

1.2 缺陷

1.連接數據庫的配置信息硬編碼 ===》存到配置文件中 2.數據庫的頻繁斷開連接==》連接池 3.sql語句,設置參數 硬編碼 ==》存到配置文件中 設置參數 反射 4.手動遍歷封裝結果集 ==》 內省

2. 自定義持久層框架

2.1 思路

2.1.1使用端

1.引入自定義持久層的包 2.提供兩部分配置信息:1.數據庫的連接配置信息 sql配置信息2.mapper.xml 存放sql配置信息

2.1.2自定義持久層框架(封裝jdbc的操作)

1.加載配置文件;根據配置文件的路徑,加載配置成字節輸入流,存儲在內存中 2.創建兩個javaBean(容器)Configuration核心配置類:存放sql的配置信息MappedStatement映射配置類 存放mapper.xml信息 3.解析配置文件 dom4j創建類sqlSessionFactoryBuilder1.使用dom4j解析配置文件,將解析出來的文件存放到javabean(容器)中2.創建sqlSessionFactory對象,生產session (工廠模式) 4.創建sqlSessionFactory接口實現類openSession 5.創建sqlSession接口及DefaultSession定義數據庫的crud操作 selectlist()update() 6.執行Exector接口及實現類SimpleExectorquery()//執行jdbc代碼

2.1.3自定義持久層框架(缺陷)

1.dao層,存在代碼重復,整個操作的過程模版重復(加載配置文件) 2.statementId存在硬編碼 ========》jdk動態代理 Proxy.newProxyInstance InvocationHandler

2.2 代碼實現

2.2.1 使用端

1.創建項目

1.創建lagou-mybatis項目(maven骨架項目)

2.創建sqlMapConfig.xml(sql源配置文件)
<configuration><!--數據庫配置信息--><dataSource><property name="driverClass" value="com.mysql.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql:///lgstudy"></property><property name="username" value="root"></property><property name="password" value="root"></property></dataSource><!--存放mapper.xml的全路徑--><mapper resource="UserMapper.xml"></mapper> </configuration>

#####2.創建UserMapper.xml(user類的sql)

<!--namespace 命名空間 當前xml的--><!--有三種全路徑:namespace綁定實體類的全路徑,綁定dao接口的全路徑,綁定mapper的sql.xml文件。第一種:namespace綁定實體類的全路徑:第二種:namespace綁定dao層接口的全路徑:第三種:namespace綁定的是mapper接口對應的sql.xml。https://www.cnblogs.com/zjdxr-up/p/8681382.html--> <mapper namespace="com.test.dao.IUserDao"><!--sql的唯一標識:namespace.id來組成 : statementId--><select id="findAll" resultType="com.test.pojo.User" >select * from user</select><select id="findOneById" resultType="com.test.pojo.User" paramterType="com.test.pojo.User">select * from user where id = #{id}</select></mapper>

2.2.2 框架端

1.創建項目

1.創建lagou-mybatis項目(maven骨架項目)

2.pojo類

Configuration 用于存儲 數據庫源

public class Configuration {private DataSource dataSource;/** key: statementid value:封裝好的mappedStatement對象* */Map<String,MappedStatement> mappedStatementMap = new HashMap<>();}

MappedStatement 用于存儲 sql文件的引用

//存儲的SQL xml文件的映射對象 public class MappedStatement {//id標識private String id;//返回值類型private String resultType;//參數值類型private String paramterType;//sql語句private String sql;}
3.io類

Resources

public class Resources {// 根據配置文件的路徑,將配置文件加載成字節輸入流,存儲在內存中public static InputStream getResourceAsSteam(String path){InputStream resourceAsStream = Resources.class.getClassLoader().getResourceAsStream(path);return resourceAsStream;} }

4.掃描類 封裝 UserMapper

public class XMLMapperBuilder {private Configuration configuration;private String namespace;public XMLMapperBuilder(Configuration configuration) {this.configuration =configuration;}public void parse(InputStream inputStream) throws DocumentException {Document document = new SAXReader().read(inputStream);Element rootElement = document.getRootElement();//獲取定義的命名空間namespace = rootElement.attributeValue("namespace");getNodes(rootElement);}public void getNodes(Element rootElement){//獲取標簽名稱String name = rootElement.getName();List<Element> list = rootElement.selectNodes("//"+name);for (Element element : list) {String id = element.attributeValue("id");String resultType = element.attributeValue("resultType");String paramterType = element.attributeValue("paramterType");String sqlText = element.getTextTrim();if(id!=null){MappedStatement mappedStatement = new MappedStatement();mappedStatement.setId(id);mappedStatement.setResultType(resultType);mappedStatement.setParamterType(paramterType);mappedStatement.setSql(sqlText);mappedStatement.setTypeValue(name);//封裝keyString key = namespace+"."+id;configuration.getMappedStatementMap().put(key,mappedStatement);}}//遞歸遍歷當前節點所有的子節點List<Element> listElement=rootElement.elements();//所有一級子節點的listfor(Element e:listElement){//遍歷所有一級子節點this.getNodes(e);//遞歸}} }

5.方法反射類

public class DefaultSqlSession implements SqlSession {private Configuration configuration;public DefaultSqlSession(Configuration configuration) {this.configuration = configuration;}@Overridepublic <E> List<E> selectList(String statementId, Object... param) throws Exception {//調用執行器//將要去完成對simpleExecutor里的query方法的調用simpleExecutor simpleExecutor = new simpleExecutor();//根據statementId獲取MappedMappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);List<Object> list = simpleExecutor.query(configuration, mappedStatement, param);return (List<E>) list;}@Overridepublic <T> T selectOne(String statementId, Object... params) throws Exception {List<Object> objects = selectList(statementId, params);if (objects.size() == 1) {return (T) objects.get(0);} else {throw new RuntimeException("查詢結果為空或者返回結果過多");}}@Overridepublic int update(String statementId, Object... params) throws Exception {simpleExecutor simpleExecutor = new simpleExecutor();MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);int update = simpleExecutor.update(configuration, mappedStatement, params);return update;}@Overridepublic <T> T getMapper(Class<?> mapperClass) {// 使用JDK動態代理來為Dao接口生成代理對象,并返回 // loader: 用哪個類加載器去加載代理對象 // interfaces:動態代理類需要實現的接口 // h:動態代理方法在執行時,會調用h里面的invoke方法去執行Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {//proxy 當前代理對象的應用//method 當前被調用方法的引用//args 傳遞的參數@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 底層都還是去執行JDBC代碼 //根據不同情況,來調用selctList或者selectOne// 準備參數 1:statmentid :sql語句的唯一標識:namespace.id= 接口全限定名.方法名// 方法名:findAllString methodName = method.getName();String className = method.getDeclaringClass().getName();Object result = new Object();String statementId = className + "." + methodName;//com.test.dao.IUserDao.updateById//com.test.dao.IUserDao.updateMappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);//獲取方法的標簽值String typeValue = mappedStatement.getTypeValue();switch (typeValue) {case "insert": {result = update(statementId, args);break;}case "update": {result = update(statementId, args);break;}case "delete": {result = update(statementId, args);break;}case "select": {Type genericReturnType = method.getGenericReturnType();// 判斷是否進行了 泛型類型參數化if (genericReturnType instanceof ParameterizedType) {List<Object> objects = selectList(statementId, args);result= objects;break;}else{result= selectOne(statementId, args);break;}}}return result;}});return (T) proxyInstance;}}

6.JDbc執行類

public class simpleExecutor implements Executor {@Override //userpublic <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {// 1. 注冊驅動,獲取連接Connection connection = configuration.getDataSource().getConnection();// 2. 獲取sql語句 : select * from user where id = #{id} and username = #{username}//轉換sql語句: select * from user where id = ? and username = ? ,轉換的過程中,還需要對#{}里面的值進行解析存儲String sql = mappedStatement.getSql();BoundSql boundSql = getBoundSql(sql);// 3.獲取預處理對象:preparedStatementPreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());// 4. 設置參數//獲取到了 參數的全路徑String paramterType = mappedStatement.getParamterType();Class<?> paramtertypeClass = getClassType(paramterType);List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();for (int i = 0; i < parameterMappingList.size(); i++) {ParameterMapping parameterMapping = parameterMappingList.get(i);String content = parameterMapping.getContent();//反射Field declaredField = paramtertypeClass.getDeclaredField(content);//暴力訪問declaredField.setAccessible(true);Object o = declaredField.get(params[0]);preparedStatement.setObject(i+1,o);}// 5. 執行sqlResultSet resultSet = preparedStatement.executeQuery();//獲取返回值類String resultType = mappedStatement.getResultType();Class<?> resultTypeClass = getClassType(resultType);ArrayList<Object> objects = new ArrayList<>();// 6. 封裝返回結果集while (resultSet.next()){//反射new一個類Object o =resultTypeClass.newInstance();//元數據ResultSetMetaData metaData = resultSet.getMetaData();for (int i = 1; i <= metaData.getColumnCount(); i++) {// 字段名String columnName = metaData.getColumnName(i);// 字段的值Object value = resultSet.getObject(columnName);//使用反射或者內省,根據數據庫表和實體的對應關系,完成封裝PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);Method writeMethod = propertyDescriptor.getWriteMethod();writeMethod.invoke(o,value);}objects.add(o);}return (List<E>) objects;}@Overridepublic int update(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {//update user set username=#{} where id=#{}// 1. 注冊驅動,獲取連接Connection connection = configuration.getDataSource().getConnection();// 2. 獲取sql語句 : select * from user where id = #{id} and username = #{username}//轉換sql語句: select * from user where id = ? and username = ? ,轉換的過程中,還需要對#{}里面的值進行解析存儲String sql = mappedStatement.getSql();BoundSql boundSql = getBoundSql(sql);// 3.獲取預處理對象:preparedStatementPreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());// 4. 設置參數//獲取到了 參數的全路徑String paramterType = mappedStatement.getParamterType();Class<?> paramtertypeClass = getClassType(paramterType);List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();for (int i = 0; i < parameterMappingList.size(); i++) {ParameterMapping parameterMapping = parameterMappingList.get(i);String content = parameterMapping.getContent();Object o =null;if(mappedStatement.getTypeValue().equals("delete")){o= params[i];}else{//反射Field declaredField = paramtertypeClass.getDeclaredField(content);//暴力訪問declaredField.setAccessible(true);o = declaredField.get(params[0]);}preparedStatement.setObject(i+1,o);}// 5. 執行sqlint i1 = preparedStatement.executeUpdate();return i1;}private Class<?> getClassType(String paramterType) throws ClassNotFoundException {if(paramterType!=null){Class<?> aClass = Class.forName(paramterType);return aClass;}return null;}/*** 完成對#{}的解析工作:1.將#{}使用?進行代替,2.解析出#{}里面的值進行存儲* @param sql* @return*/private BoundSql getBoundSql(String sql) {//標記處理類:配置標記解析器來完成對占位符的解析處理工作ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);//解析出來的sqlString parseSql = genericTokenParser.parse(sql);//#{}里面解析出來的參數名稱List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();BoundSql boundSql = new BoundSql(parseSql,parameterMappings);return boundSql;} }

7.測試類

@Test public void testProxyDao() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);User user = userMapper.findById(1);System.out.println(user);sqlSession.close(); }

2.2.3打jar問題

1.在pom文件中添加編譯屬性

<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.encoding>UTF-8</maven.compiler.encoding><java.version>1.8</java.version><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties>

2.idea中點擊 projrct Structure =>點擊module 設置項目的編譯版本
3.srtting=> builder=>compiler=>java compiler設置編譯版本

3.mybatis快速啟動

3.1導依賴

<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.encoding>UTF-8</maven.compiler.encoding><java.version>1.8</java.version><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><!--引入依賴--><dependencies><!--mybatis坐標--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><!--mysql驅動坐標--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version><scope>runtime</scope></dependency><!--單元測試坐標--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency></dependencies>

4 自定義插件

xml

<plugins><plugin interceptor="com.lagou.plugin.MyPlugin"><property name="name" value="Bob"/></plugin></plugins>

java

package com.lagou.plugin;import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.plugin.*;import java.sql.Connection; import java.util.Properties;@Intercepts({@Signature(type= StatementHandler.class,//攔截那個接口method = "prepare",//這個接口內的那個方法名args={Connection.class,Integer.class})//攔截方法的入參,如果方法重載,通過方法名跟參數確定唯一})public class MyPlugin implements Interceptor {//這里是每次執行操作的時候,都會進行這個方法@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("增強了");return invocation.proceed();}//把這個攔截器生成一個代理放到攔截器鏈中@Overridepublic Object plugin(Object target) {System.out.println("將要包裝的目標對象"+target);return Plugin.wrap(target,this);}//插件初始化時候調用,只調用一次 獲取配置文件的屬性@Overridepublic void setProperties(Properties properties) {System.out.println("獲取配置文件的屬性"+properties);}}

mybatis 攔截的類

一、executor,executor類可以說是執行sql的全過程,如組裝參數,sql改造,結果處理,比較廣泛,但實際用的不多

二、StatementHandler,這個是執行sql的過程,可以獲取到待執行的sql,可用來改造sql,如分頁,分表,最常攔截的類

三、paremeterHandler,這個用來攔截sql的參數,可以自定義參數組裝規則

四、resultHandler,這個用來處理結果

5 緩存

一級緩存

二級緩存

二級緩存是序列化存儲 需要實現POJO需要實現Serializable接口

<settings><setting name="cacheEnabled" value="true" /> </settings> //在sql的mapper的添加 <cache/>表填

問題

1.緩存使用順序

先到二級緩存當中查找 如果二級緩存中沒有,就去找一級緩存 如果一級緩存中也沒有就去到數據庫當中查詢

2.二級Chache使用原則

1.只能在一個命名空間下使用二級緩存
由于二級緩存中的數據是基于namespace的,即不同namespace中的數據互不干擾。在多個namespace中若均存在對同一個表的操作,那么這多個namespace中的數據可能就會出現不一致現象。
2.在單表上使用二級緩存
如果一個表與其它表有關聯關系,那么久非常有可能存在多個namespace對同一數據的操作。而不同namespace中的數據互補干擾,所以就有可能出現多個namespace中的數據不一致現象。
3.查詢多于修改時使用二級緩存
在查詢操作遠遠多于增刪改操作的情況下可以使用二級緩存。因為任何增刪改操作都將刷新二級緩存,對二級緩存的頻繁刷新將降低系統性能。

java補充

1.java類型 T,E,K,V,?

泛型中的通配符?表示不確定的 java 類型 ?無界通配符 例子 List<? extends Animal> listAnimalsT (type) 表示具體的一個java類型List<T>是確定的某一個類型K V (key value) 分別代表java鍵值中的Key ValueE (element) 代表Element 上界通配符 < ? extends E> 下界通配符 < ? super E>T和?運用的地方有點不同,? 是定義在引用變量上T 是類上或方法上

2. List<T.?.Object>區別

ArrayList<T> arrayList = new ArrayList<T>(); 指定集合元素類型只可以是T類型 ArrayList<?>arrayList = new ArrayList<?>(); 集合元素可以是任意類型,一般是方法中為了說明方法 ArrayList<? extends E> arrayList = new ArrayList<? extends E>();泛型的限定:? extends E:接受E類型或者E的子類型、? super E :接受E類型或者E的父類型

3.java的內省與反射

//https://www.cnblogs.com/winclpt/articles/7405271.html1.內省是先得到屬性描述器PropertyDecriptor后再進行各種操作,內省(Introspector)是Java語言對JavaBean類屬性、事件的處理方法 2.反射則是先得到類的字節碼Class后再進行各種操作的。對任意一個類,能夠獲取得到這個類的所有屬性和方法; 代碼:反射:Field f = user.getClass().getDeclaredField("name");f.setAccessible(true);f.set(user, "mld");//設置屬性值內省//操作單個屬性PropertyDescriptor pd = new PropertyDescriptor("name", User.class);Method w = pd.getWriteMethod();//獲取屬性的setter方法w.invoke(user, "winclpt");

4.java的代理

1.靜態代理

靜態代理:由程序員創建或特定工具自動生成源代碼,也就是在編譯時就已經將接口,被代理類,代理類等確定下來。在程序運行之前,代理類的.class文件就已經生成

2.動態代理

實現InvocationHandler接口
動態代理就是要生成一個包裝類對象,由于代理的對象是動態的,所以叫動態代理。由于我們需要增強,這個增強是需要留給開發人員開發代碼的,因此代理類不能直接包含被代理對象,而是一個InvocationHandler,該InvocationHandler包含被代理對象,并負責分發請求給被代理對象,分發前后均可以做增強。從原理可以看出,JDK動態代理是“對象”的代理。
原文鏈接:https://blog.csdn.net/flyfeifei66/article/details/81481222 **

// 使用JDK動態代理來為Dao接口生成代理對象,并返回 // loader: 用哪個類加載器去加載代理對象 // // interfaces:動態代理類需要實現的接口 // // h:動態代理方法在執行時,會調用h里面的invoke方法去執行Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {//proxy 當前代理對象的應用//method 當前被調用方法的引用//args 傳遞的參數@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 底層都還是去執行JDBC代碼 //根據不同情況,來調用selctList或者selectOne// 準備參數 1:statmentid :sql語句的唯一標識:namespace.id= 接口全限定名.方法名// 方法名:findAllString methodName = method.getName();String className = method.getDeclaringClass().getName();String statementId = className+"."+methodName;// 準備參數2:params:args// 獲取被調用方法的返回值類型Type genericReturnType = method.getGenericReturnType();// 判斷是否進行了 泛型類型參數化if(genericReturnType instanceof ParameterizedType){List<Object> objects = selectList(statementId, args);return objects;}return selectOne(statementId,args);}});return (T) proxyInstance;}

5.newInstance與new的區別

new關鍵字能調用任何構造方法。
newInstance()只能調用無參構造方法。
newInstance()構造對象的地方通過new關鍵字也可以創建對象.
在使用newInstance()方法的時候,必須保證這個類已經加載并且已經連接
適用:
使用newInstance()在通用性方面比較高,className我們可以用配置文件進行相關的配置。
String className = 從配置文件中讀取className;
A a = (A) Class.forName(className).newInstance();
再配合依賴注入的方法,就提高了軟件的可伸縮性、可擴展性。框架的開發中用的比較多!

public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {String str = (String) Class.forName("java.lang.String").newInstance();String str1 = new String();if(str.getClass() == str1.getClass()){System.out.println("YES");}}output:YES //原文鏈接:https://blog.csdn.net/qq_33704186/java/article/details/86596614

單詞

statement 聲明,陳述
bound 一定會,邊界
Declaring 公然地,生命
Accessible 可進入的
descrip 描述
relation 關系
example例子
Generic通用的
Security 安全的
Multiple 多樣的
extract提取
wrap包
signature簽名
Additional附加的 額外的/

作業

簡答題

一.

1.Mybatis動態sql是做什么的?

1.動態sql就是 根據條件標簽動態的拼接sql,包括判空,循環,拼接等

2.哪些動態sql?

動態sql大致有
1.: if是為了判斷傳入的值是否符合某種規則,比如是否不為空;
2.:where標簽可以用來做動態拼接查詢條件,當和if標簽配合的時候,不用顯示的聲明類似where 1=1這種無用的條件
3.:foreach標簽可以把傳入的集合對象進行遍歷,然后把每一項的內容作為參數傳到sql語句中,
4.:include可以把大量重復的代碼整理起來,當使用的時候直接include即可,減少重復代碼的編寫;
5.:是一個格式化標簽
6.choose、when、otherwise 標簽類似于 Java 中的 switch、case、default。只有一個條件生效,

<select id="findOneById" resultType="com.lagou.pojo.User">select <include refid="userInfo"/> from user<where><if test="id != null and id != 0">AND id = #{id}</if><foreach collection="list" item="id" open="(" close=")" separator="," >#{id}</foreach><trim prefix="where" suffix="order by id" prefixOverrides="and | or" suffixOverrides=","><if test="name != null and name != ''">AND name = #{name}</if><if test="id != null">AND id = #{id}</if></trim></where> </select>

3. 簡述一下動態sql的執行原理?

1.在xmlMapperBuilder中 解析配置文件時

2.解析 <mapper /> 節點

3.解析 節點

// 1.在xmlMapperBuilder中 解析配置文件時public void parse() {// 解析 `<mapper />` 節點configurationElement(parser.evalNode("/mapper"));}//2. 解析 `<mapper />` 節點private void configurationElement(XNode context) {try {// 獲得 namespace 屬性String namespace = context.getStringAttribute("namespace");if (namespace == null || namespace.equals("")) {throw new BuilderException("Mapper's namespace cannot be empty");}// 設置 namespace 屬性builderAssistant.setCurrentNamespace(namespace);// 解析 <resultMap /> 節點們resultMapElements(context.evalNodes("/mapper/resultMap"));// 解析 <sql /> 節點們sqlElement(context.evalNodes("/mapper/sql"));// 解析 <select /> <insert /> <update /> <delete /> 節點們buildStatementFromContext(context.evalNodes("select|insert|update|delete"));} catch (Exception e) {throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);}}// 3.解析 <select /> <insert /> <update /> <delete /> 節點們private void buildStatementFromContext(List<XNode> list) {if (configuration.getDatabaseId() != null) {buildStatementFromContext(list, configuration.getDatabaseId());}buildStatementFromContext(list, null);// 上面兩塊代碼,可以簡寫成 buildStatementFromContext(list, configuration.getDatabaseId());}private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {//遍歷 <select /> <insert /> <update /> <delete /> 節點們for (XNode context : list) {// 創建 XMLStatementBuilder 對象,執行解析final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);try {statementParser.parseStatementNode();} catch (IncompleteElementException e) {// 解析失敗,添加到 configuration 中configuration.addIncompleteStatement(statementParser);}}}

4.XMLStatementBuilder對象

public class XMLStatementBuilder extends BaseBuilder {/*** 執行解析*/public void parseStatementNode() {// 獲得 id 屬性,編號。String id = context.getStringAttribute("id");// 獲得 databaseId , 判斷 databaseId 是否匹配String databaseId = context.getStringAttribute("databaseId");if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {return;}// 獲得各種屬性Integer fetchSize = context.getIntAttribute("fetchSize");Integer timeout = context.getIntAttribute("timeout");String parameterMap = context.getStringAttribute("parameterMap");String parameterType = context.getStringAttribute("parameterType");Class<?> parameterTypeClass = resolveClass(parameterType);String resultMap = context.getStringAttribute("resultMap");String resultType = context.getStringAttribute("resultType");String lang = context.getStringAttribute("lang");// 獲得 lang 對應的 LanguageDriver 對象LanguageDriver langDriver = getLanguageDriver(lang);// 獲得 resultType 對應的類Class<?> resultTypeClass = resolveClass(resultType);// 獲得 resultSet 對應的枚舉值String resultSetType = context.getStringAttribute("resultSetType");ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);// 獲得 statementType 對應的枚舉值StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));}

5.LanguageDriver的實現類XMLLanguageDriver的方法解析方法createSqlSource

public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {// 創建 XMLScriptBuilder 對象,執行解析XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script, parameterType);return builder.parseScriptNode();}

6.解析

XMLScriptBuilder標簽解析 /*** XML 動態語句( SQL )構建器,負責將 SQL 解析成 SqlSource 對象** @author Clinton Begin*/ public class XMLScriptBuilder extends BaseBuilder {/*** 當前 SQL 的 XNode 對象*/private final XNode context;/*** 是否為動態 SQL*/private boolean isDynamic;/*** SQL 方法類型*/private final Class<?> parameterType;/*** NodeNodeHandler 的映射*/private final Map<String, NodeHandler> nodeHandlerMap = new HashMap<>();public XMLScriptBuilder(Configuration configuration, XNode context) {this(configuration, context, null);}public XMLScriptBuilder(Configuration configuration, XNode context, Class<?> parameterType) {super(configuration);this.context = context;this.parameterType = parameterType;// 初始化 nodeHandlerMap 屬性initNodeHandlerMap();}/*** 初始化 {@link #nodeHandlerMap} 屬性*/private void initNodeHandlerMap() {nodeHandlerMap.put("trim", new TrimHandler());nodeHandlerMap.put("where", new WhereHandler());nodeHandlerMap.put("set", new SetHandler());nodeHandlerMap.put("foreach", new ForEachHandler());nodeHandlerMap.put("if", new IfHandler());nodeHandlerMap.put("choose", new ChooseHandler());nodeHandlerMap.put("when", new IfHandler());nodeHandlerMap.put("otherwise", new OtherwiseHandler());nodeHandlerMap.put("bind", new BindHandler());}/*** 負責將 SQL 解析成 SqlSource 對象** @return SqlSource 對象*/public SqlSource parseScriptNode() {// 解析 SQLMixedSqlNode rootSqlNode = parseDynamicTags(context);// 創建 SqlSource 對象SqlSource sqlSource;if (isDynamic) {sqlSource = new DynamicSqlSource(configuration, rootSqlNode);} else {sqlSource = new RawSqlSource(configuration, rootSqlNode, parameterType);}return sqlSource;}/*** 解析 SQL 成 MixedSqlNode 對象** @param node XNode 節點* @return MixedSqlNode*/protected MixedSqlNode parseDynamicTags(XNode node) {// 創建 SqlNode 數組List<SqlNode> contents = new ArrayList<>();// 遍歷 SQL 節點的所有子節點NodeList children = node.getNode().getChildNodes();for (int i = 0; i < children.getLength(); i++) {// 當前子節點XNode child = node.newXNode(children.item(i));// 如果類型是 Node.CDATA_SECTION_NODE 或者 Node.TEXT_NODE 時if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {// 獲得內容String data = child.getStringBody("");// 創建 TextSqlNode 對象TextSqlNode textSqlNode = new TextSqlNode(data);// 如果是動態的 TextSqlNode 對象if (textSqlNode.isDynamic()) {// 添加到 contents 中contents.add(textSqlNode);// 標記為動態 SQLisDynamic = true;// 如果是非動態的 TextSqlNode 對象} else {// 創建 StaticTextSqlNode 添加到 contents 中contents.add(new StaticTextSqlNode(data));}// 如果類型是 Node.ELEMENT_NODE} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628// 根據子節點的標簽,獲得對應的 NodeHandler 對象String nodeName = child.getNode().getNodeName();NodeHandler handler = nodeHandlerMap.get(nodeName);if (handler == null) { // 獲得不到,說明是未知的標簽,拋出 BuilderException 異常throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");}// 執行 NodeHandler 處理handler.handleNode(child, contents);// 標記為動態 SQLisDynamic = true;}}// 創建 MixedSqlNode 對象return new MixedSqlNode(contents);}/*** Node 處理器接口*/private interface NodeHandler {/*** 處理 Node** @param nodeToHandle 要處理的 XNode 節點* @param targetContents 目標的 SqlNode 數組。實際上,被處理的 XNode 節點會創建成對應的 SqlNode 對象,添加到 targetContents 中*/void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);}/*** `<bind />` 標簽的處理器** @see VarDeclSqlNode*/private class BindHandler implements NodeHandler {public BindHandler() {// Prevent Synthetic Access}@Overridepublic void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {// 解析 name、value 屬性final String name = nodeToHandle.getStringAttribute("name");final String expression = nodeToHandle.getStringAttribute("value");// 創建 VarDeclSqlNode 對象final VarDeclSqlNode node = new VarDeclSqlNode(name, expression);// 添加到 targetContents 中targetContents.add(node);}}/*** `<trim />` 標簽的處理器** @see TrimSqlNode*/private class TrimHandler implements NodeHandler {public TrimHandler() {// Prevent Synthetic Access}@Overridepublic void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {// 解析內部的 SQL 節點,成 MixedSqlNode 對象MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);// 獲得 prefix、prefixOverrides、"suffix"、suffixOverrides 屬性String prefix = nodeToHandle.getStringAttribute("prefix");String prefixOverrides = nodeToHandle.getStringAttribute("prefixOverrides");String suffix = nodeToHandle.getStringAttribute("suffix");String suffixOverrides = nodeToHandle.getStringAttribute("suffixOverrides");// 創建 TrimSqlNode 對象TrimSqlNode trim = new TrimSqlNode(configuration, mixedSqlNode, prefix, prefixOverrides, suffix, suffixOverrides);// 添加到 targetContents 中targetContents.add(trim);}}/*** `<where />` 標簽的處理器** @see WhereSqlNode*/private class WhereHandler implements NodeHandler {public WhereHandler() {// Prevent Synthetic Access}@Overridepublic void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {// 解析內部的 SQL 節點,成 MixedSqlNode 對象MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);// 創建 WhereSqlNode 對象WhereSqlNode where = new WhereSqlNode(configuration, mixedSqlNode);// 添加到 targetContents 中targetContents.add(where);}}/*** `<set />` 標簽的處理器** @see SetSqlNode*/private class SetHandler implements NodeHandler {public SetHandler() {// Prevent Synthetic Access}@Overridepublic void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {// 解析內部的 SQL 節點,成 MixedSqlNode 對象MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);// 創建 SetSqlNode 對象SetSqlNode set = new SetSqlNode(configuration, mixedSqlNode);// 添加到 targetContents 中targetContents.add(set);}}/*** `<foreach />` 標簽的處理器** @see ForEachSqlNode*/private class ForEachHandler implements NodeHandler {public ForEachHandler() {// Prevent Synthetic Access}@Overridepublic void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {// 解析內部的 SQL 節點,成 MixedSqlNode 對象MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);// 獲得 collection、item、index、open、close、separator 屬性String collection = nodeToHandle.getStringAttribute("collection");String item = nodeToHandle.getStringAttribute("item");String index = nodeToHandle.getStringAttribute("index");String open = nodeToHandle.getStringAttribute("open");String close = nodeToHandle.getStringAttribute("close");String separator = nodeToHandle.getStringAttribute("separator");// 創建 ForEachSqlNode 對象ForEachSqlNode forEachSqlNode = new ForEachSqlNode(configuration, mixedSqlNode, collection, index, item, open, close, separator);// 添加到 targetContents 中targetContents.add(forEachSqlNode);}}/*** `<if />` 標簽的處理器** @see IfSqlNode*/private class IfHandler implements NodeHandler {public IfHandler() {// Prevent Synthetic Access}@Overridepublic void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {// 解析內部的 SQL 節點,成 MixedSqlNode 對象MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);// 獲得 test 屬性String test = nodeToHandle.getStringAttribute("test");// 創建 IfSqlNode 對象IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);// 添加到 targetContents 中targetContents.add(ifSqlNode);}}/*** `<otherwise />` 標簽的處理器*/private class OtherwiseHandler implements NodeHandler {public OtherwiseHandler() {// Prevent Synthetic Access}@Overridepublic void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {// 解析內部的 SQL 節點,成 MixedSqlNode 對象MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle);// 添加到 targetContents 中targetContents.add(mixedSqlNode);}}/*** `<choose />` 標簽的處理器** @see ChooseSqlNode*/private class ChooseHandler implements NodeHandler {public ChooseHandler() {// Prevent Synthetic Access}@Overridepublic void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {List<SqlNode> whenSqlNodes = new ArrayList<>();List<SqlNode> otherwiseSqlNodes = new ArrayList<>();// 解析 `<when />` 和 `<otherwise />` 的節點們handleWhenOtherwiseNodes(nodeToHandle, whenSqlNodes, otherwiseSqlNodes);// 獲得 `<otherwise />` 的節點SqlNode defaultSqlNode = getDefaultSqlNode(otherwiseSqlNodes);// 創建 ChooseSqlNode 對象ChooseSqlNode chooseSqlNode = new ChooseSqlNode(whenSqlNodes, defaultSqlNode);// 添加到 targetContents 中targetContents.add(chooseSqlNode);}private void handleWhenOtherwiseNodes(XNode chooseSqlNode, List<SqlNode> ifSqlNodes, List<SqlNode> defaultSqlNodes) {List<XNode> children = chooseSqlNode.getChildren();for (XNode child : children) {String nodeName = child.getNode().getNodeName();NodeHandler handler = nodeHandlerMap.get(nodeName);if (handler instanceof IfHandler) { // 處理 `<when />` 標簽的情況handler.handleNode(child, ifSqlNodes);} else if (handler instanceof OtherwiseHandler) { // 處理 `<otherwise />` 標簽的情況handler.handleNode(child, defaultSqlNodes);}}}// 至多允許有一個 SqlNode 節點private SqlNode getDefaultSqlNode(List<SqlNode> defaultSqlNodes) {SqlNode defaultSqlNode = null;if (defaultSqlNodes.size() == 1) {defaultSqlNode = defaultSqlNodes.get(0);} else if (defaultSqlNodes.size() > 1) {throw new BuilderException("Too many default (otherwise) elements in choose statement.");}return defaultSqlNode;}}}

二、

Mybatis是否支持延遲加載?如果支持,它的實現原理是什么?

延遲加載主要通過動態代理實現,通過代理攔截指定方法沒執行數據加載。

javassisProxyFactory會創建一個User代理對象,所有調用User對象方法,都會經過EnhancedResultObjectProxyImpl.invoke()方法的攔截。、

于是當調用User.getOrder()方法時,才真正去執行查詢Order的動作并把結果賦值

<settings><!-- 開啟全局配置的懶加載 --><setting name="lazyLoadingEnabled" value="true"/><!-- 關閉積極加載 --><setting name="aggressiveLazyLoading" value="false"/> </settings> <mapper namespace="demo.cyj.dao.TeacherDao"><select id="findTeacherByTname" resultType="Teacher" resultMap="getTeacher">select t.t_id t_id,t.t_name t_name from teacher t where t.t_name =#{name}</select>//延遲加載<resultMap type="Teacher" id="getTeacher"><collection ofType="Student" property="stuList" fetchType="lazy" column="t_name" select="findTeacherByTnameLazy" /></resultMap><select id="findTeacherByTnameLazy" resultType="Student" >select s.id id,s.stu_name stu_name,s.stu_age age,s.t_id t_id from student s left join teacher t on t.t_id = s.t_id where t.t_name=#{name} </select> </mapper>

2.延遲加載的類

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());if (closed) {throw new ExecutorException("Executor was closed.");}if (queryStack == 0 && ms.isFlushCacheRequired()) {clearLocalCache();}List<E> list;try {queryStack++;list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;if (list != null) {handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);} else {list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);}} finally {queryStack--;}if (queryStack == 0) {for (DeferredLoad deferredLoad : deferredLoads) {deferredLoad.load();}// issue #601deferredLoads.clear();if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {// issue #482clearLocalCache();}}return list;}

延遲加載的類

private static class DeferredLoad {private final MetaObject resultObject;private final String property;private final Class<?> targetType;private final CacheKey key;private final PerpetualCache localCache;private final ObjectFactory objectFactory;private final ResultExtractor resultExtractor;// issue #781public DeferredLoad(MetaObject resultObject,String property,CacheKey key,PerpetualCache localCache,Configuration configuration,Class<?> targetType) {this.resultObject = resultObject;this.property = property;this.key = key;this.localCache = localCache;this.objectFactory = configuration.getObjectFactory();this.resultExtractor = new ResultExtractor(configuration, objectFactory);this.targetType = targetType;}public boolean canLoad() {return localCache.getObject(key) != null && localCache.getObject(key) != EXECUTION_PLACEHOLDER;}public void load() {@SuppressWarnings( "unchecked" )// we suppose we get back a ListList<Object> list = (List<Object>) localCache.getObject(key);Object value = resultExtractor.extractObjectFromList(list, targetType);resultObject.setValue(property, value);}}

1.Mybatis都有哪些Executor執行器

BaseExecutor 簡單執行器,是 MyBatis 中默認使用的執行器,每執行一次 update 或 select,就開啟一個 Statement 對象,用完就直接關閉 Statement 對象(可以是 Statement 或者是 PreparedStatment 對象)
BatchExecutor 批處理執行器,用于將多個SQL一次性輸出到數據庫
simpleExexutor 每執行一次update或select,就開啟一個Statement對象,用完立刻關閉Statement對象。[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LX6M9gvA-1597914279840)(C:\Users\gaoyuan\Desktop\simpleExexutor.png)]

ReuseExecutor 執行update或select,以sql作為key查找Statement對象,存在就使用,不存在就創建,用完后,不關閉Statement對象,而是放置于Map內,供下一次使用。簡言之,就是重復使用Statement對象。

cachingExecutor 更新緩存

2.它們之間的區別是什么?

作用范圍:Executor的這些特點,都嚴格限制在SqlSession生命周期范圍內。

默認是SimplExcutor,需要配置在創建SqlSession對象的時候指定執行器的類型即可。

1.一級緩存

Mybatis的一級緩存是指SqlSession級別的,作用域是SqlSession,Mybatis默認開啟一級緩存,在同一個SqlSession中,相同的Sql查詢的時候,第一次查詢的時候,就會從緩存中取,如果發現沒有數據,那么就從數據庫查詢出來,并且緩存到HashMap中,如果下次還是相同的查詢,就直接從緩存中查詢,就不在去查詢數據庫,對應的就不在去執行SQL語句。當查詢到的數據,進行增刪改的操作的時候,緩存將會失效

2. 二級緩存

MyBatis的二級緩存是基于Mapper級別的,也就是說多個SqlSession去使用某個Mapper的查詢語句時,得到的緩存數據是可共用的。第一次調用mapper下的sql 的時候去查詢信息,查詢到的信息會存放到該mapper對應的二級緩存區域,第二次調用namespace下的mapper映射文件中,相同的SQL去查詢,回去對應的二級緩存內取結果。二級緩存開啟后,查詢就會走二級緩存,沒查到直接查庫。MyBatis默認不開啟二級緩存

簡述Mybatis的插件運行原理,以及如何編寫一個插件?

插件運行原理

實現Mybatis的Interceptor接口并復寫intercept()方法,然后在給插件編寫注解,指定要攔截哪一個接口的哪些方法即可

實現Interceptor接口 在定義StatementHandler處理器的時候攔截prepare方法也就是準備的方法

//1.configuration.newStatementHandler()獲取對象public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {Statement stmt = null;Configuration configuration = ms.getConfiguration();//定義StatementHandler處理器StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);//初始化stmt = prepareStatement(handler, ms.getStatementLog());//執行return handler.update(stmt);}//2.獲取執行sql的StatementHandler組件public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);//代理對象statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);return statementHandler;}//3.public class InterceptorChain {private final List<Interceptor> interceptors = new ArrayList<Interceptor>();public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target = interceptor.plugin(target);}return target;}}

如何編寫插件

實現Interceptor接口,Interceptors注解表明要攔截的類,方法,參數

package com.lagou.plugin;import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.plugin.*;import java.sql.Connection; import java.util.Properties;@Intercepts({@Signature(type= StatementHandler.class,//攔截那個接口method = "prepare",//這個接口內的那個方法名args={Connection.class,Integer.class})//攔截方法的入參,如果方法重載,通過方法名跟參數確定唯一})public class MyPlugin implements Interceptor {//這里是每次執行操作的時候,都會進行這個方法@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("增強了");return invocation.proceed();}//把這個攔截器生成一個代理放到攔截器鏈中@Overridepublic Object plugin(Object target) {System.out.println("將要包裝的目標對象"+target);return Plugin.wrap(target,this);}//插件初始化時候調用,只調用一次 獲取配置文件的屬性@Overridepublic void setProperties(Properties properties) {System.out.println("獲取配置文件的屬性"+properties);}}tementHandler);return statementHandler;}//3.public class InterceptorChain {private final List<Interceptor> interceptors = new ArrayList<Interceptor>();public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target = interceptor.plugin(target);}return target;}}

如何編寫插件

實現Interceptor接口,Interceptors注解表明要攔截的類,方法,參數

package com.lagou.plugin;import org.apache.ibatis.executor.statement.StatementHandler; import org.apache.ibatis.plugin.*;import java.sql.Connection; import java.util.Properties;@Intercepts({@Signature(type= StatementHandler.class,//攔截那個接口method = "prepare",//這個接口內的那個方法名args={Connection.class,Integer.class})//攔截方法的入參,如果方法重載,通過方法名跟參數確定唯一})public class MyPlugin implements Interceptor {//這里是每次執行操作的時候,都會進行這個方法@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("增強了");return invocation.proceed();}//把這個攔截器生成一個代理放到攔截器鏈中@Overridepublic Object plugin(Object target) {System.out.println("將要包裝的目標對象"+target);return Plugin.wrap(target,this);}//插件初始化時候調用,只調用一次 獲取配置文件的屬性@Overridepublic void setProperties(Properties properties) {System.out.println("獲取配置文件的屬性"+properties);}}

總結

以上是生活随笔為你收集整理的mybatis源码刨析总结的全部內容,希望文章能夠幫你解決所遇到的問題。

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

欧美xxxx性xxxxx高清 | 久久人人爽爽人人爽人人片av | 国产精品初高中精品久久 | 91精品国产91热久久久做人人 | 日韩一二区在线观看 | 国产精品国产三级国产aⅴ9色 | 国产丝袜网站 | 色爽网站 | 日韩在线观看视频一区二区三区 | 91福利免费 | 国产短视频在线播放 | 国产精品久久久久免费 | 91精品久久久久久综合乱菊 | 免费在线观看亚洲视频 | 狠狠色丁香婷婷综合欧美 | 国产精品视频你懂的 | 免费高清在线一区 | 人人舔人人 | 色天天天 | 欧美一级免费 | www.国产毛片 | 国产午夜精品一区二区三区欧美 | 久久久久久久久久久久久久免费看 | 97人人模人人爽人人少妇 | 欧美日韩国产一区 | www国产精品com| 久久99最新地址 | 在线 日韩 av | 国产精品美女久久久久久久久久久 | 最近字幕在线观看第一季 | 国产一二区精品 | 狠狠色噜噜狠狠 | 在线不卡视频 | 欧美 日韩精品 | 色国产视频 | 公开超碰在线 | av大全在线免费观看 | 人人爱在线视频 | 国产一区在线免费观看 | 免费在线观看日韩 | 精品av网站 | 国产99久久久国产精品免费看 | 成人黄色电影视频 | 亚洲成色777777在线观看影院 | 伊人天天综合 | 91传媒91久久久 | 国产精品免费久久久久久 | www.午夜视频| 狠狠干天天 | 操操操夜夜操 | 国产999精品 | 在线观看亚洲专区 | 一级a毛片高清视频 | 手机av资源 | 日韩电影一区二区在线观看 | 91视频中文字幕 | 婷婷六月中文字幕 | 欧美日韩不卡一区二区 | 日韩成人黄色 | 国产一区二区久久久 | 亚洲 中文字幕av | 黄在线免费观看 | 精品久久久久久久久久久久久 | 福利在线看片 | 国产精品第52页 | 色婷婷激情电影 | 91黄色免费看 | 精品欧美一区二区精品久久 | 美女网站在线播放 | 99在线精品免费视频九九视 | 免费在线91 | 色wwww| 精品久久久久久一区二区里番 | 色婷婷国产精品一区在线观看 | 黄色一级网 | 黄色av电影在线观看 | 99色人 | 在线观看国产一区二区 | 日韩一区二区三区免费视频 | 97国产精品免费 | 免费看的黄网站软件 | 99久久精品电影 | 国产成人高清 | 日韩高清片 | 视频国产一区二区三区 | 成片免费 | 国产精品久久久久久久久久东京 | 久久人人添人人爽添人人88v | 欧美一区二区伦理片 | 亚洲成色777777在线观看影院 | 欧美精品三级在线观看 | 国产黄色片在线 | 中文字幕在线看视频 | 日韩城人在线 | 尤物九九久久国产精品的分类 | 欧美国产日韩一区二区 | 欧美婷婷色 | 99r精品视频在线观看 | 99热这里只有精品1 av中文字幕日韩 | 久久久久综合精品福利啪啪 | 国产成人精品在线 | 免费开视频| 7777精品伊人久久久大香线蕉 | www.久热 | 久久久国产精品一区二区三区 | 欧美精品一区在线 | 午夜影院日本 | 欧美性高跟鞋xxxxhd | 欧美一级视频一区 | 黄色小网站免费看 | 国产视频亚洲 | 黄网站色| 爱爱av网站| www日日 | 国产成人一区二区啪在线观看 | 国产精品 视频 | 国产成人精品久久亚洲高清不卡 | 欧美巨大荫蒂茸毛毛人妖 | 国产精品a成v人在线播放 | 久久国产精品视频观看 | 精品国精品自拍自在线 | 国产一区久久久 | 久久久精品欧美一区二区免费 | 成人免费视频观看 | 国产1区在线 | 在线成人国产 | 天天干天天干天天干天天干天天干天天干 | 国产三级精品三级在线观看 | 久久综合婷婷 | 在线观看日韩专区 | 黄色一级大片在线免费看产 | zzijzzij日本成熟少妇 | 91在线看网站| 亚洲免费视频观看 | 91精品久久久久久久99蜜桃 | 亚洲成a人片在线观看网站口工 | 特级西西444www大精品视频免费看 | 免费精品久久久 | 日本黄网站 | 欧美精品久久久久久久久久白贞 | 成人app在线播放 | 成人亚洲免费 | www.天天成人国产电影 | 久久激情视频免费观看 | 日日夜夜爱 | 91亚洲精品久久久蜜桃 | 91精品视频免费 | 美女视频免费一区二区 | av电影不卡在线 | 五月激情av| 国内久久| 日日夜日日干 | 久久久久久久久久伊人 | 成人理论在线观看 | 草久电影 | 欧美日韩精品区 | 香蕉久久久久久久 | 最新成人在线 | 天天色天天色 | 国产美女精品 | 超碰97在线看 | 日韩精品三区四区 | 久久久在线免费观看 | 日日射av| 色综合久久五月天 | 天天色天天操天天爽 | 国内毛片毛片 | 日韩在线视频一区二区三区 | 亚洲视频第一页 | 亚洲精品视频第一页 | 欧美一二三区在线播放 | 国产麻豆成人传媒免费观看 | 丝袜av一区 | 在线观看午夜av | 日韩免费一区二区三区 | www.狠狠操.com | 精品久久久久久久久久岛国gif | 爱色婷婷 | 五月婷婷在线视频观看 | 色全色在线资源网 | 最新色视频 | 中文字幕在线人 | 高潮久久久 | 521色香蕉网站在线观看 | 日本中文字幕影院 | www四虎影院 | 欧美一级专区免费大片 | 国产福利a| 国产成人精品网站 | 亚洲黄色成人网 | 久久国产精彩视频 | 亚洲视频 中文字幕 | 美女久久久久久久 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 免费男女羞羞的视频网站中文字幕 | 91精品专区 | 久久久久福利视频 | 久久综合久久久久88 | 久久久在线观看 | 免费中文字幕视频 | 免费电影播放 | av性网站 | 久久久精华网 | 碰天天操天天 | 日韩欧美精品在线观看视频 | 天天做综合网 | 人人精品 | 国产欧美最新羞羞视频在线观看 | 深夜视频久久 | 久久69精品久久久久久久电影好 | 亚洲一二三久久 | 免费日韩高清 | av在线电影免费观看 | 日韩精品欧美专区 | 99欧美| 久久久性 | 欧美激情视频一区 | 精品亚洲欧美一区 | 超碰在线免费福利 | 亚洲视频h | 成年人免费观看国产 | 国内精品久久久久 | 久久成人资源 | 成年人免费电影 | 99久久精品免费看国产麻豆 | 欧洲精品久久久久毛片完整版 | 色综合久久久久 | 婷婷综合在线 | 久久国产一区二区 | 成人免费观看大片 | 狠狠色丁香婷婷综合欧美 | 国产精品久久网 | 久草视频中文在线 | 又污又黄的网站 | 久久久久久久久久久免费视频 | 国产欧美三级 | 国产精品一区二区av | a久久免费视频 | 狠狠躁日日躁夜夜躁av | 久久综合九色综合97_ 久久久 | 四虎在线免费观看 | 黄色亚洲大片免费在线观看 | 久久 亚洲视频 | 亚洲精品97| 在线导航av| 91精品对白一区国产伦 | 美女久久久久久久久久 | 国产伦精品一区二区三区四区视频 | 少妇高潮冒白浆 | 精品久久久久久久久久国产 | 91av免费观看 | www.久久99| 精品国产网址 | 久久经典视频 | 国产精品毛片一区二区在线 | 久久视频免费看 | 久久精品视频99 | 国产99一区二区 | 欧美一区二区三区在线视频观看 | 香蕉视频导航 | 欧美激情视频免费看 | 国产精品久久久久久久久久久免费 | 久久免费视频在线观看 | 蜜臀av一区二区 | 黄网站色| 日日夜夜天天射 | 91精品人成在线观看 | 午夜婷婷网 | 男女视频久久久 | 九色福利视频 | 91看片淫黄大片在线播放 | 日韩a在线播放 | 麻豆视频免费看 | 日韩在线视 | 免费三级影片 | 国产成人在线精品 | 在线天堂中文在线资源网 | 婷婷夜夜 | 俺要去色综合狠狠 | 亚洲精品乱码久久久久久蜜桃动漫 | 国产精品美女www爽爽爽视频 | 91在线免费观看国产 | 99精品国产aⅴ | 西西人体4444www高清视频 | 久草视频在线观 | 五月激情婷婷丁香 | 久草在线免费色站 | 九九久久精品 | 久久激情视频网 | 免费观看完整版无人区 | a在线观看国产 | 日韩高清一二三区 | 玖玖在线观看视频 | 久久视频二区 | 欧美日韩高清一区二区 | 在线免费观看国产 | 久久久久日本精品一区二区三区 | 日韩三级中文字幕 | 日本中文字幕在线视频 | 手机在线视频福利 | 免费午夜av | 黄色国产高清 | 五月婷婷六月综合 | 亚洲一区免费在线 | 狠狠狠色丁香综合久久天下网 | 日韩视频在线一区 | 美女视频黄频 | 国产一级电影 | 国产精品每日更新 | 国产精品久久久久久久av大片 | 亚洲欧美偷拍另类 | 国产高清视频在线 | 狠狠色丁香婷婷综合久小说久 | 国产色视频网站2 | 久久国产精品99国产精 | 日韩在线一级 | 久热免费在线 | 久久国产a| 国产视频二区三区 | 黄色软件在线观看免费 | 日韩欧美一区二区三区黑寡妇 | 在线观看的av| 天天操伊人 | 婷婷草 | 欧美嫩草影院 | 久久黄色美女 | 91在线91| 中文字幕 国产视频 | 免费观看一级一片 | 国产在线观看中文字幕 | 日韩精品欧美视频 | 国产精品原创av片国产免费 | 91精品久久久久久久久久入口 | 久久这里有精品 | 91av视频免费在线观看 | 成人免费毛片aaaaaa片 | 人人涩 | 欧美色插| 中中文字幕av在线 | 一区二区av | 日韩在线免费电影 | 天堂麻豆 | 国产aa精品| 国产高清网站 | 国产很黄很色的视频 | 久久草草热国产精品直播 | 欧美黑人xxxx猛性大交 | 欧美日韩一区二区在线 | 日韩精品欧美视频 | 婷婷精品进入 | 黄色片视频免费 | 天天干天天干天天色 | 日本中文不卡 | 色综合中文字幕 | 亚洲精品综合在线观看 | 92av视频 | av大全在线看 | 欧美一区二区三区免费观看 | 亚洲精品电影在线 | 国产精品一区在线观看 | avove黑丝| 黄色软件在线看 | 中文字幕刺激在线 | 久久精品国产一区二区三区 | 国产一区二区在线精品 | 国产福利小视频在线 | 欧美日韩国产一区二区在线观看 | 欧美一级特黄高清视频 | 偷拍精品一区二区三区 | 中文字幕免费在线看 | av一区二区三区在线播放 | 中字幕视频在线永久在线观看免费 | 又黄又色又爽 | www.com.黄| 欧美一二三区在线观看 | 日本在线观看一区二区三区 | 五月天激情婷婷 | 日韩精品中文字幕一区二区 | 精品福利在线观看 | 日韩中文在线观看 | 在线91网| 中文国产成人精品久久一 | 波多野结衣日韩 | 一级黄视频 | 久久最新网址 | 在线观看视频色 | 在线免费色 | 色婷婷综合久久久中文字幕 | 成人高清在线 | 啪啪资源| 国产伦理一区二区三区 | 91精品999 | 国产成人精品女人久久久 | www.色五月| 久久精品国产亚洲a | 精品网站999www| 美国av大片 | 91.精品高清在线观看 | 在线观看中文字幕亚洲 | 国产精品美女视频网站 | 成人天堂网| 国产精品一区二区62 | 国产一区二区在线免费播放 | 久久精品视频免费播放 | 国产香蕉97碰碰久久人人 | 天天做夜夜做 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 日韩精品中文字幕在线不卡尤物 | 亚洲h色精品 | 狠狠干综合网 | 国产精品视频地址 | 很黄很污的视频网站 | 99精品视频在线观看 | 97色婷婷 | 黄在线免费观看 | 久草在线91 | 久草热视频 | 九色91视频| 五月综合色| 中文字幕av免费观看 | 91精品国产乱码久久 | 欧美精品首页 | 亚洲精品在线一区二区三区 | 久久www免费人成看片高清 | 久色婷婷| 久久夜色网 | 在线免费观看黄色小说 | 色成人亚洲网 | 久久久色 | 国产精品久久久久久久久久久免费看 | 在线你懂 | 国产成人一区二区精品非洲 | 欧美视屏一区二区 | 一级免费看| 国产成人333kkk | 最近免费中文字幕mv在线视频3 | 欧美日本国产在线观看 | 不卡视频一区二区三区 | 伊人影院av | 91在线影视 | 有码中文在线 | 麻豆视频在线观看免费 | 国产一级免费电影 | 97福利| 91精品成人久久 | 综合网婷婷 | 黄色精品一区二区 | 狠狠久久婷婷 | 五月婷婷激情综合 | 午夜视频99 | 98超碰在线| 波多野结衣在线观看一区二区三区 | 手机看片国产 | 精品国产一区二区三区不卡 | 樱空桃av| 成人在线视频一区 | 精品久久久久久国产 | 成人a级黄色片 | 日韩中文字幕亚洲一区二区va在线 | 久久99精品一区二区三区三区 | 欧美久久久一区二区三区 | 久久综合五月天婷婷伊人 | 99热超碰 | 中文字幕免费成人 | 久久久久久久久久影院 | 国产高清在线a视频大全 | 中文字幕观看在线 | 91看片成人 | 国产精品专区h在线观看 | 亚洲一区二区视频在线 | 日日干天天插 | 中国一级特黄毛片大片久久 | 免费日韩一级片 | 99久久久久久 | 国产精品久久久久四虎 | 天堂网一区二区 | 国产一区二区三区视频在线 | 外国av网 | 日韩理论片在线 | 伊人久操 | 99久久这里只有精品 | 天天操天天操 | 久久久久国产a免费观看rela | 毛片网站观看 | 极品嫩模被强到高潮呻吟91 | 色综合天天爱 | 国产涩涩网站 | 麻豆精品传媒视频 | 国产精品 中文字幕 亚洲 欧美 | 青青网视频 | 久青草影院 | 日韩成人中文字幕 | 成人午夜电影在线观看 | 久久精品99国产精品亚洲最刺激 | 黄色网址在线播放 | 麻豆视频免费入口 | av中文字幕网站 | 欧美一区二区三区特黄 | 激情综合交 | 97av视频在线 | 精品久久久久久久久中文字幕 | 欧美色精品天天在线观看视频 | 最近更新好看的中文字幕 | 一区二区三区四区五区在线视频 | 婷婷六月天天 | 中文字幕一区二区三区在线观看 | wwwwwww黄 | 激情视频免费观看 | 狠狠躁天天躁 | 波多野结衣一区二区三区中文字幕 | 亚洲精品乱码久久久久久按摩 | 国产成人免费在线 | 亚洲精品在线网站 | 欧美一区二区在线免费看 | 欧美色图88 | 精品免费国产一区二区三区四区 | 国产无限资源在线观看 | 天天人人综合 | 人人精品 | 视频 国产区 | 国产一区二区三区四区在线 | 日本狠狠色 | 97精品国自产拍在线观看 | 精品国产理论片 | 国产精品久久久久久久久毛片 | 国内精品久久久久国产 | 国产h在线观看 | 99c视频高清免费观看 | 一区二区激情视频 | 国产精品久免费的黄网站 | 欧亚日韩精品一区二区在线 | 天天综合网久久综合网 | 国产成人1区 | 国产一区成人 | 美国av片在线观看 | 天天操天天干天天爱 | 日韩色区 | 欧美成年性 | www.国产毛片 | 在线a视频免费观看 | av免费看网站 | 国产999精品久久久久久绿帽 | 国产一区二区视频在线播放 | 在线视频精品播放 | 国产高清视频在线播放一区 | 97人人看| 国产成人专区 | 久久人人爽爽 | 成人av手机在线 | 国产理论在线 | 国产精品一区二区在线免费观看 | 亚洲欧美日韩精品一区二区 | 激情动态 | 国产精品免费久久久 | 国产中文字幕在线看 | 中文字幕一区在线观看视频 | 日韩精品你懂的 | 天堂va欧美va亚洲va老司机 | 久久久久久在线观看 | 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 99热最新精品 | 在线亚洲成人 | 91麻豆传媒 | 亚洲高清av| 国产精品麻豆三级一区视频 | 欧美成人性战久久 | 日本护士三级少妇三级999 | 六月婷婷网| 国产精品久久久久久久久毛片 | 欧美另类交在线观看 | 很黄很黄的网站免费的 | 六月丁香在线观看 | 青草草在线 | 亚洲精品福利视频 | 免费高清在线一区 | 一区二区三区四区五区六区 | 精品久久久久久久久久岛国gif | 国产精品久久久久久久久软件 | 久久久久久在线观看 | 免费看污污视频的网站 | 久久久久国产精品午夜一区 | 亚洲国产美女精品久久久久∴ | 婷婷六月色 | 婷婷夜夜 | 亚洲午夜久久久综合37日本 | 九九热免费在线观看 | 中文字幕国产一区二区 | 天天干天天做 | 欧美日本一二三 | 人成午夜视频 | 一本—道久久a久久精品蜜桃 | 日韩精品一区二区在线观看视频 | 国产精品久久久久久久久久尿 | 久久手机看片 | 在线观看中文字幕av | 亚洲精品88欧美一区二区 | 免费av 在线| 精品亚洲免费 | 久久久三级视频 | 亚洲精品美女久久久久网站 | 视频在线国产 | 在线观看成人毛片 | 国产99精品| 色婷婷综合久久久中文字幕 | 天天爽夜夜操 | 天天干天天摸天天操 | 色五月色开心色婷婷色丁香 | 国产精品久久久久永久免费观看 | 最新中文字幕在线播放 | 久久丁香网 | 国产精品嫩草影院99网站 | 亚洲三级在线播放 | 亚洲少妇xxxx | 久久久久久久久久久久av | 黄色在线免费观看网址 | 天天干天天拍天天操天天拍 | 婷婷色网视频在线播放 | 久久伦理视频 | 免费大片av | 狠狠干狠狠久久 | 毛片在线网| 香蕉视频久久久 | 91视频免费看片 | 免费在线看成人av | 日av免费 | aaa日本高清在线播放免费观看 | 最新日韩在线观看 | 成人播放器 | www.91av在线 | av免费播放| av中文字幕不卡 | 免费看十八岁美女 | 97福利在线观看 | 91插插影库 | jizzjizzjizz亚洲| 天天色图| 成人播放器 | 超碰最新网址 | 久久好看| 欧美激情综合五月色丁香 | 黄色免费大全 | 黄色a在线观看 | 中文字幕高清免费日韩视频在线 | 综合精品久久 | 日韩中文字幕网站 | 伊人成人久久 | 成人免费xyz网站 | 国产亚洲精品久久久久久无几年桃 | 一区二区三区视频 | 国产精品一区二区久久国产 | 视色网站| 欧美日韩一区二区免费在线观看 | 午夜婷婷在线播放 | 国产人成看黄久久久久久久久 | 久久久久久久久久伊人 | 欧美欧美 | www视频在线免费观看 | 日韩91av| 日韩二区三区在线观看 | 婷婷丁香社区 | 日韩系列在线观看 | 夜夜操网站| 亚洲人成在线电影 | 久久成人久久 | 久久国产精品99久久久久久丝袜 | 亚洲码国产日韩欧美高潮在线播放 | 激情中文在线 | 久久综合射 | 日韩精品久久久久 | 日韩在线视频在线观看 | 国产日韩一区在线 | 久草爱视频 | 久久毛片网站 | 日韩动态视频 | 欧洲精品久久久久毛片完整版 | 欧美少妇的秘密 | 天天爽天天做 | 亚洲精品欧美精品 | 国产资源av | 97视频在线观看网址 | 日韩免费一区二区在线观看 | 日韩超碰| 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 亚洲无线视频 | 韩国av免费 | 日韩视频一区二区三区 | 日韩h在线观看 | 国产手机精品视频 | 国产精品久久久久9999 | 999久久久免费精品国产 | 国内精品久久久久影院优 | 五月婷婷综合激情 | 91成人亚洲| 日韩一级黄色片 | 国产日韩精品视频 | av黄色av| 久久久久综合 | 日韩毛片精品 | 亚洲国产精品一区二区久久,亚洲午夜 | 日日干美女 | 日韩a级免费视频 | 黄色官网在线观看 | 91成人在线观看高潮 | 美女免费网站 | 操操爽| 人人射人人爱 | 在线 国产一区 | 国产成人精品一区二区三区免费 | 热99久久精品 | 美女网站在线观看 | 欧美韩日视频 | 久久久久久久免费 | 天天躁天天操 | 久久婷婷国产 | 国产福利一区二区三区在线观看 | 久久综合狠狠 | 亚洲视频2| 韩日精品视频 | 欧美日韩一区二区视频在线观看 | 九九九毛片 | www婷婷 | 天堂av高清 | 欧美激情视频久久 | 一级一片免费观看 | 黄色软件视频网站 | 蜜臀av一区| 国产精品女人久久久 | 日韩精品一区二区三区三炮视频 | 国产三级香港三韩国三级 | 91久久爱热色涩涩 | 日本久久91 | 黄色大片免费网站 | 黄污视频大全 | 天天射天天操天天 | 99亚洲天堂 | 国产中文字幕一区二区三区 | 四虎最新入口 | 中文字幕亚洲欧美日韩 | 久久精品伊人 | 天天综合久久 | 麻豆91精品 | 在线观看一区视频 | 三级黄色片在线观看 | 国产成人av电影在线观看 | 在线观看mv的中文字幕网站 | 婷婷av在线| 欧美激情在线网站 | 在线观看自拍 | 中文有码在线 | 波多野结衣视频一区二区 | 91一区二区三区在线观看 | 国产免费叼嘿网站免费 | 国产精品男女视频 | 青青河边草观看完整版高清 | 国产高清无av久久 | 久久99电影 | 天天干天天摸 | 免费成视频 | 国产精品久久久久av免费 | 日日爱夜夜爱 | 日本夜夜草视频网站 | 国产成人亚洲精品自产在线 | 午夜黄色一级片 | 黄色福利网 | 亚洲干 | 日韩不卡高清视频 | 久久精品久久久精品美女 | 国产特级毛片aaaaaa | 九九视频在线 | 天天射,天天干 | 在线视频日韩精品 | 日韩综合在线观看 | 日韩免费中文 | 国产精品高潮呻吟久久久久 | 超碰在线98 | 在线之家免费在线观看电影 | 亚洲电影免费 | 免费看国产精品 | 96亚洲精品久久久蜜桃 | 99热精品在线观看 | 成人黄色电影免费观看 | 国内精品在线观看视频 | 激情av五月婷婷 | 国产激情免费 | 国产原创中文在线 | 色欧美综合 | 久久久国产精品麻豆 | 中文字幕在线成人 | 天天射天天做 | 日批视频在线播放 | 亚洲精品黄 | 国产91九色蝌蚪 | 欧美网址在线观看 | 五月天国产 | 在线小视频你懂得 | 亚洲色图 校园春色 | 91精品啪在线观看国产81旧版 | 日韩欧美在线视频一区二区三区 | 国产在线精品国自产拍影院 | 尤物97国产精品久久精品国产 | 国产高清精品在线 | 亚洲最新视频在线 | 久久久精品午夜 | 色视频成人在线观看免 | 午夜黄网| 天天爽夜夜爽人人爽曰av | 欧美日产在线观看 | 97福利社 | 国产在线观看中文字幕 | 夜夜躁狠狠躁日日躁 | 99精品国产福利在线观看免费 | 日韩综合色 | 2023年中文无字幕文字 | 中国一级片在线播放 | 久久国产精品99久久久久 | 深爱婷婷网 | 园产精品久久久久久久7电影 | 菠萝菠萝在线精品视频 | 日韩欧美一区二区不卡 | 久久久久久久网 | 亚洲精品视频在线免费 | 亚洲电影图片小说 | 精品女同一区二区三区在线观看 | 中文字幕精品一区二区三区电影 | 国产精品成人自产拍在线观看 | 欧美片网站yy | 国产精品美女久久久 | 日韩三区在线观看 | 欧美午夜久久久 | 国产美女主播精品一区二区三区 | 中文区中文字幕免费看 | 国产在线2020 | 久久精品网址 | 91在线区 | 91九色国产蝌蚪 | 最近的中文字幕大全免费版 | 亚洲动漫在线观看 | 久久精品高清 | 国产美女精品久久久 | 亚洲免费观看在线视频 | 欧美日韩国产一区二区三区在线观看 | 狠狠操操操 | 久久国语露脸国产精品电影 | 波多野结衣在线视频免费观看 | 丁香六月激情婷婷 | 在线天堂中文在线资源网 | 啪啪精品| 日韩一区二区三免费高清在线观看 | 婷婷色中文网 | 色婷五月| 国产精品高潮呻吟久久av无 | 福利久久| 精品免费观看 | 亚洲毛片视频 | 国产99久久久国产 | 中午字幕在线观看 | 女人久久久久 | 99r精品视频在线观看 | 人人玩人人添人人澡超碰 | www.色就是色 | 久久久久久久久国产 | 亚洲欧美婷婷六月色综合 | av综合站| 日韩精品中文字幕在线观看 | 亚洲精品久久视频 | 亚洲影院一区 | 日韩啪啪小视频 | 综合久久网 | 黄色软件视频大全免费下载 | 国产精品系列在线 | 色视频网站在线观看一=区 a视频免费在线观看 | 婷婷激情五月综合 | 成人久久视频 | 久久综合九色综合欧美狠狠 | 在线免费观看av网站 | 国产精品久久久久影院 | 日韩色综合网 | 五月开心色 | 狠狠干成人 | 这里只有精彩视频 | 国产成人一区二区三区 | 一区二区三区在线免费 | 久久久久国产一区二区三区四区 | 亚洲综合激情五月 | 精品麻豆| 成人国产精品一区 | 色播五月激情五月 | 欧美日本不卡视频 | 手机在线日韩视频 | 黄色在线观看污 | 亚洲无在线 | 日韩理论电影网 | 亚洲一区美女视频在线观看免费 | 亚洲小视频在线观看 | www.夜夜爱 | 国产精品丝袜久久久久久久不卡 | 粉嫩一区二区三区粉嫩91 | 国内精品久久影院 | 国产福利中文字幕 | 久久爱综合 | 视频一区视频二区在线观看 | 免费在线一区二区三区 | 丰满少妇一级片 | 国产成人精品一区二区三区在线观看 | 欧美日韩在线观看一区二区 | 国产精品乱码久久 | 五月天伊人| 97精品国产91久久久久久 | 亚洲无在线 | 日韩三级在线 | 欧美日韩在线精品一区二区 | 亚洲精品视频在线 | 日韩免费不卡av | 狠狠操91| 99久久综合狠狠综合久久 | 国产在线超碰 | 97超碰在线视 | 国产美女主播精品一区二区三区 | 午夜91在线| 日韩网站在线看片你懂的 | 精品国产伦一区二区三区观看方式 | 99久久婷婷国产精品综合 | 91精品视频免费在线观看 | 久久久久综合精品福利啪啪 | 精品国偷自产在线 | 亚洲精品麻豆视频 | 免费看国产精品 | 就色干综合 | 精品国产欧美一区二区三区不卡 | 午夜久久影视 | 天堂资源在线观看视频 | 久久综合欧美精品亚洲一区 | 欧美日韩性视频 | 久久久久久久久久久久影院 | 国产精品日韩在线播放 | 91精品伦理 | 美女黄频网站 | 中文字幕免费高 | 成片视频在线观看 | 国产高清无av久久 | 久久字幕精品一区 | 韩国三级一区 | 在线观看网站av | 国产又粗又猛又黄视频 | 999毛片| 久久69精品久久久久久久电影好 | 中文字幕乱码一区二区 | 特级毛片网 | 免费在线观看a v | 天天做日日做天天爽视频免费 | 婷婷在线精品视频 | 97超碰人人爱 | 国产1区2| 国产精品18毛片一区二区 | 99re亚洲国产精品 | 日韩动态视频 | 国产美女黄网站免费 | 欧美色婷婷 | 亚洲国产精品久久久久久 | 国产精品 日韩精品 | 久久久久国产成人免费精品免费 | 在线导航av | 国产精品18久久久久久不卡孕妇 | 久久手机在线视频 | 久久精品香蕉 | 国产精品麻豆99久久久久久 | 九草视频在线观看 | 国产高清免费 | 国产91精品一区二区绿帽 | 99亚洲精品 | 久久久午夜视频 | 久久久www免费电影网 | 国产一区二三区好的 | 亚洲精品视频在线播放 | 四虎国产精品免费 | 亚洲日本黄色 | 久久草精品 | 久草免费在线视频观看 | 国产黄色a| 日韩高清无线码2023 | 精品一区 在线 | 欧美日韩一区二区在线 | 91精品日韩 | 91精品视频观看 | 成年人在线免费看视频 | 国产精品一区二区在线播放 | 激情www| 激情五月婷婷 | 天天艹天天 | 国产日韩欧美视频在线观看 | 91精品1区| 成人精品一区二区三区中文字幕 | 久久免费视频2 | zzijzzij日本成熟少妇 | 九九九九热精品免费视频点播观看 | 国产午夜三级 | 欧美久草网 | 国产精品久久久久久一二三四五 |